/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/


#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <memory.h>

#include "contributors.h"
#include "global.h"
#include "macroblock.h"
#include "vlc.h"
#include "block.h"
#include "header.h"
#include "golomb.h"
#include "ratectl.h"
#include "adaptiverounding.h"  //N11 liwr
#include "qcoder.h"

extern const byte QP_SCALE_CR[64];
extern const int NCBP[64][2];

int predict_error, dq;

int DELTA_QP, DELTA_QP2;

int QP, QP2;

byte **intra_pred, **inter_pred;

#define INVALID 8
static const byte step_y[MAX_MODE_NUM] = {INVALID , INVALID , 1       , INVALID , 1}; //8 is a invalid value
static const byte step_x[MAX_MODE_NUM] = {INVALID , INVALID , INVALID , 1       , 1};

extern cs_ptr_t cs_sb;
extern cs_ptr_t cs_sb_best;


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void store_coding_state( cs_ptr_t cs )
{
    macroblock_t *currMB = &( img->mb_data[img->curr_mb_nr] );

    cs->curr_se_nr = currMB->curr_se_nr;
    memcpy( cs->bitstream   , curr_stream         , sizeof( bitstream_t ) );
    memcpy( cs->bit_counter , currMB->bit_counter , MAX_BITCOUNTER_MB * sizeof( int ) );
    curr_stream->stream_buffer = rdo_stream->stream_buffer;

    memcpy( cs->qcoder, qcoder, sizeof( qcoder_env_t ) );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void reset_coding_state( cs_ptr_t cs )
{
    macroblock_t *currMB = &( img->mb_data[img->curr_mb_nr] );

    currMB->curr_se_nr = cs->curr_se_nr;
    memcpy( curr_stream         , cs->bitstream   , sizeof( bitstream_t ) );
    memcpy( currMB->bit_counter , cs->bit_counter , MAX_BITCOUNTER_MB * sizeof( int ) );

    memcpy( qcoder, cs->qcoder, sizeof( qcoder_env_t ) );
}


int get_recon_distortion_8x8( int block8x8 )
{
    int y, x, j, i, d = 0;
    int off_x = 8 * ( block8x8 % 2 );
    int off_y = 8 * ( block8x8 / 2 );
    for ( y = 0; y < B8_SIZE; y++ )
    {
        j = img->pix_y + y;
        for ( x = 0; x < B8_SIZE; x++ )
        {
            i = img->pix_x + x;
            d += img->quad[img_y_org[j+off_y][i+off_x] - p_img_y_rec[j+off_y][i+off_x]];
        }
    }
    return d;
}


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int get_intra_mode_cost()
{
    //now only calculate the SAD value of intra mode
    int y, x, cost = 0;
    get_residual( I8MB, img->org_y_data, intra_pred, img->y_residual );

    for ( y = 0; y < MB_BLOCK_SIZE; y++ )
    {
        for ( x = 0; x < MB_BLOCK_SIZE; x++ )
        {
            cost += RFM_ABS( img->y_residual[y][x] );
        }
    }
    return cost;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void y_recon( int no_zero_count, const byte pred[MB_BLOCK_SIZE][MB_BLOCK_SIZE] )
{
    int i, j;
    if ( no_zero_count <= 5 )
    {
        for ( j = 0; j < MB_BLOCK_SIZE; j++ )
        {
            memcpy( &p_img_y_rec[img->pix_y+j][img->pix_x], &/*intra_*/pred[j][0], MB_BLOCK_SIZE*sizeof( byte ) );
        }
    }
    else
    {
        for ( j=0; j<MB_BLOCK_SIZE; j++ )
        {
            for ( i=0; i<MB_BLOCK_SIZE; i++ )
            {
                p_img_y_rec[img->pix_y+j][img->pix_x+i] = img->y_residual[j][i] /*+ pred[j][i]*/;
            }
        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void uv_recon( int no_zero_count, const byte pred[MB_BLOCK_SIZE][MB_BLOCK_SIZE],int uv )
{
    int i, j;
    if ( no_zero_count <= 5 )
    {
        for ( j = 0; j < B8_SIZE; j++ )
        {
            memcpy( &p_img_uv_rec[uv][img->pix_c_y+j][img->pix_c_x], pred[j], B8_SIZE*sizeof( byte ) );
        }
    }
    else
    {
        for ( j=0; j<B8_SIZE; j++ )
        {
            for ( i=0; i<B8_SIZE; i++ )
            {
                p_img_uv_rec[uv][img->pix_c_y+j][img->pix_c_x+i] = img->uv_residual[uv][j][i] + pred[j][i];
            }
        }
    }
}



int write_luma_intra_mode( int intramode, int block8x8, int block4x4 )
{
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];

    int *bitCount             = currMB->bit_counter;
    int no_bits = 0;
    int code_bits = 0;
    //write luma intra modes
    code_bits = qcoder_encode_intra_luma_mode( qcoder, intramode ); //  rong 100407
    bitCount[BITS_MB_MODE] += code_bits;
    no_bits += code_bits;

    return no_bits;
}


static int write_chroma_intra_mode()
{
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];

    int *bitCount             = currMB->bit_counter;
    int no_bits = 0;
    //int y, x;
    int code_bits = 0;

    //write chroma intra modes
    code_bits = qcoder_encode_intra_chroma_mode( qcoder, currMB->uvmode );
    bitCount[BITS_MB_MODE] += code_bits;
    no_bits += code_bits;
    return no_bits;
}


int write_block_mvd( macroblock_t *currMB, int blocksize, int block8x8, int block4x4, int brdopt )
{
    int j = block8x8 /2;
    int i = block8x8 %2 ;
    int rate = 0;
    int *bitCount = currMB->bit_counter;
    int code_len = 0;

    switch( blocksize )
    {
    case 16:
        if ( currMB->b8_ref[0][0] != BI )
        {
            //code_len = qcoder_encode_mvd_x(qcoder, currMB->mvd[0][0].x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->mvd[0][0].y);
            code_len  = qcoder_encode_mvd_x_num( qcoder, currMB->mvd[0][0].x, NUM_MVD_CX_16x16_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->mvd[0][0].y, NUM_MVD_CX_16x16_QCODER );
            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
        else
        {
            //code_len  = qcoder_encode_mvd_x(qcoder, currMB->bi_mvd[0][0].fw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd[0][0].fw_mvd.y);
            //code_len += qcoder_encode_mvd_x(qcoder, currMB->bi_mvd[0][0].bw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd[0][0].bw_mvd.y);

            code_len  = qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd[0][0].fw_mvd.x, NUM_MVD_CX_16x16_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd[0][0].fw_mvd.y, NUM_MVD_CX_16x16_QCODER );
            code_len += qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd[0][0].bw_mvd.x, NUM_MVD_CX_16x16_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd[0][0].bw_mvd.y, NUM_MVD_CX_16x16_QCODER );

            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
#if TRACE
        if ( trace_out && !brdopt )
        {
            if ( p_trace )
            {
                fprintf( p_trace, "MVD_x_16x16 is: %5d\n", currMB->mvd[0][0].x );
                fprintf( p_trace, "MVD_y_16x16 is: %5d\n", currMB->mvd[0][0].y );
            }
        }
#endif
        break;
    case 8:
        if ( currMB->b8_ref[j][i] != BI )
        {
#if TRACE
            if ( trace_out &&  !brdopt )
            {
                if ( p_trace )
                {
                    fprintf( p_trace, "MVD_x_8x8 is: %5d\n", currMB->mvd[j][i].x );
                    fprintf( p_trace, "MVD_y_8x8 is: %5d\n", currMB->mvd[j][i].y );
                }
            }
#endif
            //code_len = qcoder_encode_mvd_x(qcoder, currMB->mvd[j][i].x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->mvd[j][i].y);
            code_len  = qcoder_encode_mvd_x_num( qcoder, currMB->mvd[j][i].x, NUM_MVD_CX_8x8_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->mvd[j][i].y, NUM_MVD_CX_8x8_QCODER );

            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
        else
        {
            //code_len = qcoder_encode_mvd_x(qcoder, currMB->bi_mvd[j][i].fw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd[j][i].fw_mvd.y);
            //code_len += qcoder_encode_mvd_x(qcoder, currMB->bi_mvd[j][i].bw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd[j][i].bw_mvd.y);

            code_len =  qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd[j][i].fw_mvd.x, NUM_MVD_CX_8x8_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd[j][i].fw_mvd.y, NUM_MVD_CX_8x8_QCODER );
            code_len += qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd[j][i].bw_mvd.x, NUM_MVD_CX_8x8_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd[j][i].bw_mvd.y, NUM_MVD_CX_8x8_QCODER );

            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
        break;
    case 4:
        if ( currMB->b4_ref[block8x8][block4x4] != BI )
        {
#if TRACE
            if ( trace_out && !brdopt )
            {
                if ( p_trace )
                {
                    fprintf( p_trace, "MVD_x_4x4 is: %5d\n", currMB->mvd_4x4[block8x8][block4x4].x );
                    fprintf( p_trace, "MVD_y_4x4 is: %5d\n", currMB->mvd_4x4[block8x8][block4x4].y );
                }
            }
#endif
            //code_len  = qcoder_encode_mvd_x(qcoder, currMB->mvd_4x4[block8x8][block4x4].x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->mvd_4x4[block8x8][block4x4].y);

            code_len  = qcoder_encode_mvd_x_num( qcoder, currMB->mvd_4x4[block8x8][block4x4].x, NUM_MVD_CX_4x4_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->mvd_4x4[block8x8][block4x4].y, NUM_MVD_CX_4x4_QCODER );

            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
        else
        {
            //code_len  = qcoder_encode_mvd_x(qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].fw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].fw_mvd.y);
            //code_len += qcoder_encode_mvd_x(qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].bw_mvd.x);
            //code_len += qcoder_encode_mvd_y(qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].bw_mvd.y);

            code_len  = qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].fw_mvd.x, NUM_MVD_CX_4x4_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].fw_mvd.y, NUM_MVD_CX_4x4_QCODER );
            code_len += qcoder_encode_mvd_x_num( qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].bw_mvd.x, NUM_MVD_CX_4x4_QCODER );
            code_len += qcoder_encode_mvd_y_num( qcoder, currMB->bi_mvd_4x4[block8x8][block4x4].bw_mvd.y, NUM_MVD_CX_4x4_QCODER );

            bitCount[BITS_INTER_MB] += code_len;
            rate += code_len;
        }
        break;
    default:
        assert( 1 );
    }
    return code_len;
}

int write_dqp()
{
    int rate = 0;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    int *bitCount = currMB->bit_counter;
    int code_len = 0;
    if( currMB->cbp && !input->fixed_pic_qp )
    {
        code_len = qcoder_encode_delta_qp( qcoder, currMB->delta_qp );
        bitCount[BITS_DELTA_QUANT_MB] += code_len;
        rate += code_len;
    }
    return rate;
}

/*
static int write_block_subblock_size()
{
  macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
  int *bitCount             = currMB->bit_counter;
  int blocksize,subblocksize;
  int code_len = 0;
  int block8x8;

  blocksize = currMB->mb_type==INTER16x16? 1:0;
  code_len = qcoder_encode_blocksize(qcoder, blocksize);

  if( currMB->mb_type==INTER8x8)
  {
    for (block8x8 = 0; block8x8 < 4; block8x8 ++)
    {
      if(input->ABTen&&input->InterABTen)
      {
        subblocksize = (currMB->subblock_type[block8x8]== SUBBLOCK_INTRA8x8||currMB->subblock_type[block8x8]== SUBBLOCK_INTER8x8)?0:1;//8x8 or 4x4
        code_len += qcoder_encode_subblocksize(qcoder, subblocksize);
      }
    }
  }
  bitCount[BITS_MB_MODE] += code_len;
  return code_len;
}


static int write_pred_direction()
{
  macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
  int *bitCount             = currMB->bit_counter; //xy_110915
  int i;
  int direction;
  int code_len = 0;
  int block8x8;


  if(currMB->mb_type == INTER8x8 )
  {
    for (block8x8 = 0; block8x8 < 4; block8x8 ++)
    {

      if(currMB->subblock_type[block8x8] ==SUBBLOCK_INTRA8x8 )
      {
        direction = INTRA;
        code_len += qcoder_encode_pred_direction(qcoder, direction);
        code_len += write_luma_intra_mode(currMB->b8mode[block8x8/2][block8x8%2],block8x8,0);
      }
      else if(currMB->subblock_type[block8x8] == SUBBLOCK_INTRA4x4)
      {
        for(i=0; i<4; i++)
        {
          direction = INTRA;
          code_len += qcoder_encode_pred_direction(qcoder, direction);
          code_len += write_luma_intra_mode(currMB->b4mode[block8x8/2][block8x8%2][i/2][i%2],block8x8,i);
        }
      }
      else if(currMB->subblock_type[block8x8] ==SUBBLOCK_INTER8x8)
      {
        if(img->type == P_IMG)
        {
          direction = FW;
          code_len += qcoder_encode_pred_direction(qcoder, direction);
        }
        else
        {
          direction = currMB->b8_ref[block8x8/2][block8x8%2];
          code_len += qcoder_encode_pred_direction(qcoder, direction);
        }
      }
      else
      {
        for(i=0; i<4; i++)
        {
          if(img->type == P_IMG)
          {
            direction = FW;
            code_len += qcoder_encode_pred_direction(qcoder, direction);
          }
          else
          {
            direction = currMB->b4_ref[block8x8][i];
            code_len += qcoder_encode_pred_direction(qcoder, direction);
          }
        }

      }
    }
  }
  else
  {
    if(img->type == P_IMG)
    {
      direction = FW;
      code_len += qcoder_encode_pred_direction(qcoder, direction);
    }
    else
    {
      direction = currMB->b8_ref[0][0];
      code_len += qcoder_encode_pred_direction(qcoder, direction);

    }
  }

  bitCount[BITS_MB_MODE] += code_len;
  return code_len;
}

*/
int write_skip_flag()
{
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;
    int code_len = 0;

    code_len = qcoder_encode_inter_skip( qcoder, currMB->mb_type == SKIP ? 1:0 );


    bitCount[BITS_MB_MODE] += code_len;

    if( !glb_rdopt )
        img->cod_counter = 0;
    return code_len;

}

int write_block_coeff8x8( int b8 )
{
    int no_bits               = 0;
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;

    int inumcoeff = 64;
    int icoef;
    int ipos;
    int *ACLevel;
    int *ACRun;

    int coeff[64];
    int coeff_ptr = 0;
    int pos = 0;
    int eobFlag = 0;
    int code_len = 0;
    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;

    /************************************************************************/
    /*                   8x8                                                */
    /************************************************************************/

    ipos = 0;
    ACLevel = img->cofAC[b8][0][0];
    ACRun = img->cofAC[b8][0][1];

    // Accumulate Run-Level info
    for ( icoef = 0; icoef < inumcoeff; icoef++ )
    {
        if ( !ACLevel[icoef] )
            break;
        pos += ACRun[icoef];
        coeff[pos++] = ACLevel[icoef];
        coeff_ptr++;
    }

    for( ipos=0; ipos < pos; )
    {
        code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
        no_bits += code_len;
        bitCount[BITS_COEFF_Y_MB] += code_len;

        if( !eobFlag )
        {
            do
            {
                code_len = qcoder_encode_luma_8x8_coeff( qcoder, ipos, coeff[ipos], isintra );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;
                ipos++;
            }
            while( coeff[ipos-1]==0 );
        }
    }
    if( ipos!=64 )
    {
        eobFlag = 1;
        code_len = qcoder_encode_eobflag_8x8( qcoder, eobFlag, ipos );
        no_bits += code_len;
        bitCount[BITS_COEFF_Y_MB] += code_len;
    }

    return no_bits;
}

int write_block_coeff4x4( int b8, int b4 )
{
    int no_bits               = 0;
    macroblock_t *currMB      = &img->mb_data[img->curr_mb_nr];
    int *bitCount             = currMB->bit_counter;

    int inumcoeff = 16;
    int icoef;
    int ipos;
    int *ACLevel;
    int *ACRun;

    int coeff[64];
    int coeff_ptr = 0;
    int pos = 0;
    int eobFlag = 0;
    int code_len = 0;

    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 64*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;

    ACLevel  =  img->cofAC[b8][b4][0];
    ACRun  =  img->cofAC[b8][b4][1];

    // Accumulate Run-Level info
    for ( icoef = 0; icoef < inumcoeff; icoef++ )
    {
        if ( !ACLevel[icoef] )
            break;
        pos += ACRun[icoef];
        coeff[pos++] = ACLevel[icoef];
        coeff_ptr++;
    }

    for( ipos=0; ipos < pos; )
    {
        code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
        no_bits += code_len;
        bitCount[BITS_COEFF_Y_MB] += code_len;

        if( !eobFlag )
        {
            do
            {
                code_len = qcoder_encode_luma_4x4_coeff( qcoder, ipos, coeff[ipos], isintra );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;
                ipos++;
            }
            while( coeff[ipos-1]==0 );
        }
    }
    if( ipos!=16 )
    {
        eobFlag = 1;
        code_len = qcoder_encode_eobflag_4x4( qcoder, eobFlag, ipos );
        no_bits += code_len;
        bitCount[BITS_COEFF_Y_MB] += code_len;
    }

    return no_bits;

}
static void write_one_macroblock( int eos_bit )
{
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    int *bitCount        = currMB->bit_counter;
    int no_bits = 0;

    int block8x8,block4x4;
    int k;
    int direction;
    int blocksize,subblocksize;

    no_bits += write_skip_flag();

    if( currMB->mb_type != SKIP )
    {
        blocksize = ( currMB->mb_type == INTER16x16 || img->type == I_IMG )? 1:0;
        no_bits +=qcoder_encode_blocksize( qcoder, blocksize );

        if( blocksize ) //INTER16x16 && I_IMG
        {
            if( img->type != I_IMG )
            {
                no_bits += qcoder_encode_pred_direction( qcoder, currMB->b8_ref[0][0] );
                no_bits += write_block_mvd( currMB, 16,0,0,0 ); //mvd
                for ( k = 0; k < 4; k++ ) //block16()
                    write_block_coeff8x8( k );
            }
            else				//I_IMG
            {
                no_bits += qcoder_encode_pred_direction( qcoder, INTRA );

                for( block8x8=0; block8x8<4; block8x8++ )
                {
                    if ( input->ABTen&&input->IABTen )  //vbs_enable
                    {
                        no_bits += qcoder_encode_subblocksize( qcoder, currMB->subblock_type[block8x8]==SUBBLOCK_INTRA8x8? 0:1 );  //subBlockSize (block8x8)

                        if ( currMB->subblock_type[block8x8] == SUBBLOCK_INTRA8x8 ) //8x8
                        {
#if INTRA_MODE_ADAPTIVE
                            no_bits += write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 ); //lumaIntraMode(i)
#endif
                            no_bits += write_block_coeff8x8( block8x8 ); //block8()  write_block8_coeff not defined
                        }
                        else  //4x4
                        {
                            for( block4x4=0; block4x4<4; block4x4++ )
                            {
#if INTRA_MODE_ADAPTIVE
                                no_bits += write_luma_intra_mode( currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2],block8x8,block4x4 ); //lumaIntraMode(i)
#endif
                                no_bits += write_block_coeff4x4( block8x8, block4x4 ); //block4()  write_block4_coeff not defined
                            }
                        }
                    }
                    else
                    {
                        //no_bits += qcoder_encode_subblocksize(qcoder, 0);    //subBlockSize (block8x8)

                        if ( currMB->subblock_type[block8x8] == SUBBLOCK_INTRA8x8 ) //8x8
                        {
#if INTRA_MODE_ADAPTIVE
                            no_bits += write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 ); //lumaIntraMode(i)
#endif
                            no_bits += write_block_coeff8x8( block8x8 ); //block8()  write_block_coeff not defined
                        }
                    }
                }
#if INTRA_MODE_ADAPTIVE_CHROMA
                no_bits += write_chroma_intra_mode();   //chromaIntraMode
#endif
            }
        }
        else  //Inter 8x8
        {
            for( block8x8=0; block8x8<4; block8x8++ )
            {
                subblocksize = ( currMB->subblock_type[block8x8]== SUBBLOCK_INTRA8x8||currMB->subblock_type[block8x8]== SUBBLOCK_INTER8x8 )?0:1; //8x8 or 4x4
                no_bits += qcoder_encode_subblocksize( qcoder, subblocksize );  //subBlockSize
                if( subblocksize == 0 ) //8x8
                {
                    if( currMB->subblock_type[block8x8] ==SUBBLOCK_INTRA8x8 ) //subMBSpatialTemporalPredictionDirection
                    {
                        direction = INTRA;
                        no_bits += qcoder_encode_pred_direction( qcoder, direction );
#if INTRA_MODE_ADAPTIVE
                        no_bits += write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 );
#endif
                    }
                    else
                    {
                        direction = currMB->b8_ref[block8x8/2][block8x8%2];
                        no_bits += qcoder_encode_pred_direction( qcoder, direction );
                        write_block_mvd( currMB, 8, block8x8, 0, 0 );
                    }
                    no_bits += write_block_coeff8x8( block8x8 ); //block8()  write_block_coeff not defined
                }
                else   //4x4
                {
                    for( block4x4=0; block4x4<4; block4x4++ )
                    {
                        if( currMB->subblock_type[block8x8] == SUBBLOCK_INTRA4x4 ) //direction
                        {
                            direction = INTRA;
                            no_bits += qcoder_encode_pred_direction( qcoder, direction );
#if INTRA_MODE_ADAPTIVE
                            no_bits += write_luma_intra_mode( currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2],block8x8,block4x4 );
#endif
                        }
                        else
                        {
                            if( img->type == P_IMG )
                            {
                                direction = FW;
                                no_bits += qcoder_encode_pred_direction( qcoder, direction );
                            }
                            else
                            {
                                direction = currMB->b4_ref[block8x8][block4x4];
                                no_bits += qcoder_encode_pred_direction( qcoder, direction );
                            }
                            write_block_mvd( currMB, 4, block8x8, block4x4, 0 );
                        }
                        no_bits += write_block_coeff4x4( block8x8, block4x4 ); //block4()  write_block4_coeff not defined
                    }
                }

            }
        }
        for( block8x8=4; block8x8<6; block8x8++ )
        {
            no_bits += write_chroma_coeff_b8_qcoder( block8x8 );;
        }
    }


    bitCount[BITS_TOTAL_MB] = bitCount[BITS_MB_MODE] + bitCount[BITS_COEFF_Y_MB] + bitCount[BITS_INTER_MB] + bitCount[BITS_CBP_MB] + bitCount[BITS_DELTA_QUANT_MB] + bitCount[BITS_COEFF_UV_MB];
    stat->bit_slice += bitCount[BITS_TOTAL_MB];

    img->mb_header_bits  = bitCount[BITS_MB_MODE] + bitCount[BITS_INTER_MB] + bitCount[BITS_CBP_MB] + bitCount[BITS_DELTA_QUANT_MB];
    img->mb_texture_bits = bitCount[BITS_COEFF_Y_MB] + bitCount[BITS_COEFF_UV_MB];
    img->number_of_texture_bits += img->mb_texture_bits;
    img->number_of_header_bits  += img->mb_header_bits;
    if ( img->basic_unit < img->total_mb_num )
    {
        img->number_of_basic_unit_header_bits  += img->mb_header_bits;
        img->number_of_basic_unit_texture_bits += img->mb_texture_bits;
    }

    img->coded_mb++;
}


static int y_coding16( macroblock_t * currMB )
{
    int rate=0;
    currMB->cbp  = 0;
    currMB->transform_16x16 = 1;    //

    memcpy( img->b16_residual[0],&img->y_residual[0][0],256*sizeof( int ) );
    transform_B16( img->b16_residual );
    scanquant_B16( img->vbs_qp_16x16, currMB->mb_type==5?4:0, img->b16_residual, img->type==B_IMG/*?*/, &( currMB->cbp_16x16 ) );
    rate += write_luma_coeff_b16_qcoder( currMB->mb_type==I8MB );
    return rate;
}

static int y_coding8in4( macroblock_t * currMB ) //intra 8x8-4x4
{
    int i, j,k,m, block8x8, block4x4, rate=0, rate8=0, rate8in4=0;
    int d8,d8in4;
    double rdcost8,rdcost8in4;
    int off_y, off_x;
    int temp_cbp;
    int tmp_dc;
    byte tmp_img_y_rec[8][8];
    int ACLevel_4x4[4][17],ACRun_4x4[4][17];
    int ACLevel_8x8[65],ACRun_8x8[65];
    int cbp_8x8;//cbp_4x4;
    currMB->cbp  = 0;
    currMB->transform_16x16 = 0;
    for ( block8x8=0; block8x8<4; block8x8++ )
    {
        off_x = 8 * ( block8x8 % 2 );
        off_y = 8 * ( block8x8 / 2 );
        currMB->transform_4x4[block8x8] = 0;
        currMB->subblock_type[block8x8] = SUBBLOCK_INTRA8x8;
        for ( j=0; j<8; j++ )
        {
            memcpy( img->b8_residual[j], &img->y_residual[j+off_y][off_x], 8*sizeof( int ) );
        }
        //  8x8
        store_coding_state( cs_sb );

        rate8 = qcoder_encode_subblocksize( qcoder, 0 );

        transform_b8( img->b8_residual );
        scanquant_b8( currMB->qp, ( currMB->mb_type==I8MB||currMB->mb_type==I4MB ), block8x8, img->b8_residual, &( currMB->cbp ), &temp_cbp );

#if INTRA_MODE_ADAPTIVE
        rate8 += write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 );
#endif
        rate8 += write_block_coeff8x8( block8x8 );

        //  get distortion 8x8
        d8 = get_recon_distortion_8x8( block8x8 );
        rdcost8 = d8 + img->lambda_mode * rate8;

#if RDO_STAT
        {
            printf( "          Intra8x8: Rate: %6d, Distortion: %6d, Rdcost: %6.2f \n", rate8, d8, rdcost8 );
        }
#endif

        cbp_8x8 = currMB->cbp;
        //  store reconstructed picture
        for( j=0; j<8; j++ )
            for( i=0; i<8; i++ )
                tmp_img_y_rec[j][i] = p_img_y_rec[img->pix_y+off_y+j][img->pix_x+off_x+i];
        //
        if( input->AdaptiveRounding )
            set_qadjust_to_best1_y();
        //  store level run
        for( i=0; i<65; i++ )
        {
            ACLevel_8x8[i]  =  img->cofAC[block8x8][0][0][i];
            ACRun_8x8[i]    =  img->cofAC[block8x8][0][1][i];
        }
        store_coding_state( cs_sb_best );
        reset_coding_state( cs_sb );
        //*****************************************************
        //            4x4
        //*****************************************************
        //store_coding_state(cs_abt8in4);
        for ( j=0; j<8; j++ )
        {
            memcpy( img->b8_residual[j], &img->y_residual[j+off_y][off_x], 8*sizeof( int ) );
        }
        //  set transform4x4
        currMB->transform_4x4[block8x8] = 1;
        currMB->subblock_type[block8x8] = SUBBLOCK_INTRA4x4;
        //
        rate8in4 = qcoder_encode_subblocksize( qcoder, 1 );

        for ( block4x4=0; block4x4<4; block4x4++ )
        {
            trans_scanquant_b4( img->vbs_qp_4x4,4,block8x8, block4x4, img->b8_residual, ACLevel_4x4[block4x4], ACRun_4x4[block4x4] );
#if INTRA_MODE_ADAPTIVE
            rate8in4 += write_luma_intra_mode( currMB->b4mode[block8x8/2][block8x8%2][block4x4/2][block4x4%2], block8x8,block4x4 );
#endif
            rate8in4 += write_block_coeff4x4( block8x8, block4x4 );
        }

        //  get distortion
        d8in4 = get_recon_distortion_8x8( block8x8 );
        rdcost8in4 = d8in4 + img->lambda_mode * rate8in4;

#if RDO_STAT
        {
            printf( "          Intra4x4: Rate: %6d, Distortion: %6d, Rdcost: %6.2f \n\n", rate8in4, d8in4, rdcost8in4 );
        }
#endif

        //  compare 8x8 4x4
        if ( rdcost8in4<rdcost8 )  //  choose 4x4
        {
            for( i=0; i<4; i++ )
                for( j=0; j<17; j++ )
                {
                    img->cofAC[block8x8][i][0][j] = ACLevel_4x4[i][j];
                    img->cofAC[block8x8][i][1][j] = ACRun_4x4[i][j];
                }
            currMB->cbp |= ( ( currMB->cbp_4x4[block8x8]!=0 )<<block8x8 );
            currMB->transform_4x4[block8x8] = 1;
            currMB->subblock_type[block8x8] = SUBBLOCK_INTRA4x4;
            rate += rate8in4;
            tmp_dc = 0;
            i=block8x8/2;
            j=block8x8%2;
            for ( k=0; k<2; k++ )
                for ( m=0; m<2; m++ )
                    tmp_dc += currMB->y_4x4_dc[i][j][k][m];
            currMB->y_dc[i][j] = ( tmp_dc+1 )/2;
            if( input->AdaptiveRounding )
                set_qadjust_to_best1_y();
        }
        else            //  choose 8x8
        {
            if( input->AdaptiveRounding )
                set_best1_to_qadjust();
            //  reset transform_4x4
            currMB->transform_4x4[block8x8] = 0;
            currMB->subblock_type[block8x8] = SUBBLOCK_INTRA8x8;
            for( i=0; i<65; i++ )
            {
                img->cofAC[block8x8][0][0][i]  =  ACLevel_8x8[i];
                img->cofAC[block8x8][0][1][i]  =  ACRun_8x8[i];
            }
            currMB->cbp = cbp_8x8;
            rate += rate8;
            //  reset reconstructed picture
            for( j=0; j<8; j++ )
                for( i=0; i<8; i++ )
                    p_img_y_rec[img->pix_y+off_y+j][img->pix_x+off_x+i] = tmp_img_y_rec[j][i] ;

            reset_coding_state( cs_sb_best );
        }
    }
    return rate;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int y_coding( macroblock_t * currMB ) //Inter 16x16 or Intra non-ABT coding
{
    int block8x8, rate=0;
    int off_y, off_x, y, x, j;
    int temp_cbp=0;
    currMB->cbp  = 0;
    for ( block8x8=0; block8x8<4; block8x8++ )
    {
        x = block8x8 % 2;
        y = block8x8 / 2;
        off_x = 8 * x;
        off_y = 8 * y;
        currMB->transform_4x4[block8x8] = 0;
        for ( j=0; j<8; j++ )
        {
            memcpy( &img->b8_residual[j][0], &img->y_residual[off_y+j][off_x], 8*sizeof( int ) );
        }

        if( currMB->mb_type == INTER16x16 )
        {
            //RDO for 8x8 all 0 coeff, check if all 0 is better
            int b8_y = off_y;
            int b8_x = off_x;
            prob_context_t eob_ctx = qcoder->cx_eob_flag_8x8[0];
            int lps_interval = eob_ctx.prob_fsm[eob_ctx.state].lps_interval;
            int interval = qcoder -> interval;
            int mps_interval = interval - lps_interval;
            int mps = eob_ctx.mps;
            int d8_all0 = 0;
            double rate8_all0, cost8_all0;
            double cost8;
            int x,y;
            int rate8;
            int d8;

            if ( ( mps && lps_interval<mps_interval ) || ( !mps && lps_interval>mps_interval ) )
            {
                rate8_all0 = log( ( double )interval/( double )mps_interval ) / log( 2.0 );
            }
            else
            {
                rate8_all0 = log( ( double )interval/( double )lps_interval ) / log( 2.0 );
            }
            //  get distortion 8x8 all0
            for ( y = 0; y < B8_SIZE; y++ )
            {
                for ( x = 0; x < B8_SIZE; x++ )
                {
                    d8_all0 += img->quad[img->b8_residual[y][x]];
                }
            }
            cost8_all0 = d8_all0 + img->lambda_mode * ( rate8_all0 );
            transform_b8( img->b8_residual );
            scanquant_b8( currMB->qp, ( currMB->mb_type==I8MB||currMB->mb_type==I4MB ), block8x8, img->b8_residual, &( currMB->cbp ), &temp_cbp );
            rate8 = write_block_coeff8x8( block8x8 );
            //  get distortion 8x8
            d8 = get_recon_distortion_8x8( block8x8 );
            cost8 = d8 + img->lambda_mode * ( rate8 );
            if ( cost8_all0 < cost8 )
            {
                for ( y = 0; y < B8_SIZE; y++ )
                {
                    for ( x = 0; x < B8_SIZE; x++ )
                    {
                        p_img_y_rec[img->pix_y+b8_y+y][img->pix_x+b8_x+x] = inter_pred[b8_y+y][b8_x+x];
                    }
                }
                img->cofAC[block8x8][0][0][0] = 0;
                rate8 = write_block_coeff8x8( block8x8 );
            }
            rate += rate8;
        }
        else
        {
            transform_b8( img->b8_residual );
            scanquant_b8( currMB->qp, ( currMB->mb_type==I8MB||currMB->mb_type==I4MB ), block8x8, img->b8_residual, &( currMB->cbp ),&temp_cbp );
#if INTRA_MODE_ADAPTIVE
            if( currMB->mb_type==I8MB||currMB->mb_type==I4MB )
                rate += write_luma_intra_mode( currMB->b8mode[block8x8/2][block8x8%2],block8x8,0 );
#endif
            rate += write_block_coeff8x8( block8x8 );
        }
    }
    if( input->AdaptiveRounding )
        set_qadjust_to_best1_y();
    return rate;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
//static int y_coding4(macroblock_t * currMB)
//{
//  int i, j,k,m, block8x8, rate=0, rate8in4=0;
//  int d8in4;
//  double rdcost8in4;
//  int off_y, off_x;
//  int temp_cbp;
//  int tmp_dc;
//  int ACLevel_4x4[4][17],ACRun_4x4[4][17];
//  currMB->cbp  = 0;
//  currMB->transform_16x16 = 0;
//  for (block8x8=0; block8x8<4; block8x8++)
//  {
//    off_x = 8 * (block8x8 % 2);
//    off_y = 8 * (block8x8 / 2);
//
//    store_coding_state(cs_abt8in4);
//    for (j=0; j<8; j++)
//    {
//      memcpy(img->b8_residual[j], &img->y_residual[j+off_y][off_x], 8*sizeof(int));
//    }
//    //  set transform4x4
//    currMB->transform_4x4[block8x8] = 1;
//    //
//    transform_b8inb4(img->b8_residual);
//    scanquant_b8inb4(img->vbs_qp_4x4, (currMB->mb_type==I8MB||currMB->mb_type==I4MB)?4:0, block8x8, img->b8_residual, img->type==B_IMG/*?*/, &(currMB->cbp), &temp_cbp,ACLevel_4x4, ACRun_4x4, &(currMB->cbp_4x4[block8x8]));
//    rate8in4 = write_block_coeff(block8x8);
//    //  get distortion
//    d8in4 = get_recon_distortion_8x8(block8x8);
//    rdcost8in4 = d8in4 + img->lambda_mode * rate8in4;
//
//    for(i=0;i<4;i++)
//      for(j=0;j<17;j++)
//      {
//        img->cofAC[block8x8][i][0][j] = ACLevel_4x4[i][j];
//        img->cofAC[block8x8][i][1][j] = ACRun_4x4[i][j];
//      }
//
//    currMB->cbp |= ((currMB->cbp_4x4[block8x8]!=0)<<block8x8);
//    currMB->transform_4x4[block8x8] = 1;
//    rate += rate8in4;
//    tmp_dc = 0;
//    i=block8x8/2;j=block8x8%2;
//    for (k=0;k<2;k++)
//      for (m=0;m<2;m++)
//        tmp_dc += currMB->y_4x4_dc[i][j][k][m];
//    currMB->y_dc[i][j] =  (tmp_dc+1)/2;
//    reset_coding_state(cs_abt8in4);
//  }
//  return rate;
//}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int uv_coding( macroblock_t *currMB, int uv )
{
    int rate=0;

    transform_b8( img->uv_residual[uv] );
    scanquant_b8( currMB->qp_chroma, currMB->mb_type==I8MB, 4+uv, img->uv_residual[uv], &( currMB->cbp ),&( currMB->cbp_16x16 ) ); //ChromaQP [9/17/2011 Will]
    rate += write_chroma_coeff_b8_qcoder( 4+uv );
    return rate;
}

#if INTRA_MODE_ADAPTIVE
static void decide_y_intra_mode_16()
{
    int y;
    int dc_diff[3], min_diff;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];


    memcpy( img->b16_residual[0],&img->y_residual[0][0],256*sizeof( int ) );
    transform_B16( img->b16_residual );
    quant_B16( img->vbs_qp_16x16, currMB->mb_type==5?4:0, img->b16_residual );

    currMB->y_16x16_dc = img->b16_residual[0][0];
    currMB->y_16x16_dc_diff = currMB->y_16x16_dc;
    currMB->y_16x16_dc_pred = 0;

    if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        currMB->b16mode = INTRA_NO;
    }
    else if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        min_diff = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_16x16_dc ) ) //select <= to prefer to the small mode
        {
            //the following is the same reason
            currMB->b16mode = INTRA_LEFT;
            currMB->y_16x16_dc_diff = min_diff;
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        }
    }
    else if( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        min_diff = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_16x16_dc ) )
        {
            currMB->b16mode = INTRA_UP;
            currMB->y_16x16_dc_diff = min_diff;
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        }
    }
    else if ( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )&& ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        dc_diff[INTRA_LEFT] = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        dc_diff[INTRA_UP]   = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        dc_diff[INTRA_NO]   = currMB->y_16x16_dc;
        min_diff = MAX_VALUE;
        for ( y=0; y<3; y++ )
        {
            if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
            {
                min_diff = dc_diff[y];
                currMB->b16mode = y;
            }
        }
        currMB->y_16x16_dc_diff = min_diff;
        switch( currMB->b16mode )
        {
        case INTRA_LEFT:
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
            break;
        case INTRA_UP:
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
            break;
        }
    }
}

void decide_y_intra_b8_mode( int block8x8 )
{
    int dc_diff[3], min_diff;
    int pix_y, pix_x;
    int y;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];

#define LEFT_MB_DC_DIFF(y,x) (currMB->y_dc[y][0] - img->mb_data[img->curr_mb_nr-1].y_dc[y][1])
#define UP_MB_DC_DIFF(y,x)   (currMB->y_dc[0][x] - img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][x])
#define LEFT_B8_DC_DIFF(y,x) (currMB->y_dc[y][1] - currMB->y_dc[y][0])
#define UP_B8_DC_DIFF(y,x)   (currMB->y_dc[1][x] - currMB->y_dc[0][x])

    switch ( block8x8 )
    {
    case 0:
        if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) )&& ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
        {
            currMB->b8mode[0][0] = INTRA_NO;
        }
        else if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
        {
            min_diff = LEFT_MB_DC_DIFF( 0,0 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_dc[0][0] ) ) //select <= to prefer to the small mode
            {
                //the following is the same reason
                currMB->b8mode[0][0] = INTRA_LEFT;
                currMB->y_dc_diff[0][0] = min_diff;
                currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
            }
        }
        else if( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
        {
            min_diff = UP_MB_DC_DIFF( 0,0 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_dc[0][0] ) )
            {
                currMB->b8mode[0][0] = INTRA_UP;
                currMB->y_dc_diff[0][0] = min_diff;
                currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
            }
        }
        else if ( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )&& ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
        {
            dc_diff[INTRA_LEFT] = LEFT_MB_DC_DIFF( 0,0 );
            dc_diff[INTRA_UP]   = UP_MB_DC_DIFF( 0,0 );
            dc_diff[INTRA_NO]   = currMB->y_dc[0][0];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b8mode[0][0] = y;
                }
            }
            currMB->y_dc_diff[0][0] = min_diff;
            switch( currMB->b8mode[0][0] )
            {
            case INTRA_LEFT:
                currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
                break;
            case INTRA_UP:
                currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
                break;
            }
        }
        break;
    case 1:
        pix_y = img->pix_y;
        pix_x = img->pix_x+8;
        if ( !pix_y||( pix_y&&img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) )
        {
            min_diff = LEFT_B8_DC_DIFF( 0,1 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_dc[0][1] ) )
            {
                currMB->b8mode[0][1] = INTRA_LEFT;
                currMB->y_dc_diff[0][1] = min_diff;
                currMB->y_dc_pred[0][1] = currMB->y_dc[0][0];
            }
        }
        else if( img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )
        {
            dc_diff[INTRA_LEFT] = LEFT_B8_DC_DIFF( 0,1 );
            dc_diff[INTRA_UP]   = UP_MB_DC_DIFF( 0,1 );
            dc_diff[INTRA_NO]   = currMB->y_dc[0][1];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b8mode[0][1] = y;
                }
            }
            currMB->y_dc_diff[0][1] = min_diff;
            switch( currMB->b8mode[0][1] )
            {
            case INTRA_LEFT:
                currMB->y_dc_pred[0][1] = currMB->y_dc[0][0];
                break;
            case INTRA_UP:
                currMB->y_dc_pred[0][1] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][1];
                break;
            }
        }
        break;
    case 2:
        pix_y = img->pix_y+8;
        pix_x = img->pix_x;
        if ( !pix_x||( pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) )
        {
            min_diff = UP_B8_DC_DIFF( 1,0 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_dc[1][0] ) )
            {
                currMB->b8mode[1][0]    = INTRA_UP;
                currMB->y_dc_diff[1][0] = min_diff;
                currMB->y_dc_pred[1][0] = currMB->y_dc[0][0];
            }
        }
        else if( img->mb_data[img->curr_mb_nr-1].mb_type==I8MB )
        {
            dc_diff[INTRA_LEFT] = LEFT_MB_DC_DIFF( 1,0 );
            dc_diff[INTRA_UP]   = UP_B8_DC_DIFF( 1,0 );
            dc_diff[INTRA_NO]   = currMB->y_dc[1][0];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b8mode[1][0] = y;
                }
            }
            currMB->y_dc_diff[1][0] = min_diff;
            switch( currMB->b8mode[1][0] )
            {
            case INTRA_LEFT:
                currMB->y_dc_pred[1][0] = img->mb_data[img->curr_mb_nr-1].y_dc[1][1];
                break;
            case INTRA_UP:
                currMB->y_dc_pred[1][0] = currMB->y_dc[0][0];
                break;
            }
        }
        break;
    case 3:
        dc_diff[INTRA_LEFT] = LEFT_B8_DC_DIFF( 1,1 );
        dc_diff[INTRA_UP]   = UP_B8_DC_DIFF( 1,1 );
        dc_diff[INTRA_NO]   = currMB->y_dc[1][1];
        min_diff = MAX_VALUE;
        for ( y=0; y<3; y++ )
        {
            if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
            {
                min_diff = dc_diff[y];
                currMB->b8mode[1][1] = y;
            }
        }
        currMB->y_dc_diff[1][1] = min_diff;
        switch( currMB->b8mode[1][1] )
        {
        case INTRA_LEFT:
            currMB->y_dc_pred[1][1] = currMB->y_dc[1][0];
            break;
        case INTRA_UP:
            currMB->y_dc_pred[1][1] = currMB->y_dc[0][1];
            break;
        }
        break;
    }
}

void decide_y_intra_b4_mode( int block4x4 )
{
    int i,j,k,m;
    int y;
    int dc_diff[3], dc_pred[3], min_diff;
    int pix_y, pix_x;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
#define LEFT_MB_DC_DIFF_4x4(i,j,k,m) (currMB->y_4x4_dc[i][0][k][0] - (img->mb_data[img->curr_mb_nr-1].y_dc[i][1]>>1))
#define UP_MB_DC_DIFF_4x4(i,j,k,m)   (currMB->y_4x4_dc[0][j][0][m] - (img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][j]>>1))

    i = block4x4/8;
    j = ( block4x4-8*i )/4;
    k = ( block4x4-8*i-4*j )/2;
    m = block4x4-8*i-4*j-2*k;
    switch ( block4x4 )
    {
    case 0:
        if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
        {
            currMB->b4mode[0][0][0][0] = INTRA_NO;
        }
        else if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
        {
            min_diff = LEFT_MB_DC_DIFF_4x4( 0,0,0,0 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_4x4_dc[0][0][0][0] ) ) //select <= to prefer to the small mode
            {
                //the following is the same reason
                currMB->b4mode[0][0][0][0] = INTRA_LEFT;
                currMB->y_4x4_dc_diff[0][0][0][0] = min_diff;
                currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1]>>1;//img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
            }
        }
        else if( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
        {
            min_diff = UP_MB_DC_DIFF_4x4( 0,0,0,0 );
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_4x4_dc[0][0][0][0] ) )
            {
                currMB->b4mode[0][0][0][0] = INTRA_UP;
                currMB->y_4x4_dc_diff[0][0][0][0] = min_diff;
                currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0]>>1;//img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
            }
        }
        else if ( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )&& ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
        {
            dc_diff[INTRA_LEFT] = LEFT_MB_DC_DIFF_4x4( 0,0,0,0 );
            dc_diff[INTRA_UP]   = UP_MB_DC_DIFF_4x4( 0,0,0,0 );
            dc_diff[INTRA_NO]   = currMB->y_4x4_dc[0][0][0][0];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b4mode[0][0][0][0] = y;
                }
            }
            currMB->y_4x4_dc_diff[0][0][0][0] = min_diff;
            switch( currMB->b4mode[0][0][0][0] )
            {
            case INTRA_LEFT:
                currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1]>>1;//img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
                break;
            case INTRA_UP:
                currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0]>>1;//img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
                break;
            }
        }
        break;
    case 1:
    case 4:
    case 5:
        //b4_idx=1,4,5 upper bound
        pix_y = img->pix_y;
        pix_x = img->pix_x+8*j+4*m;
        if ( m )    //  1,5
        {
            dc_diff[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][1]-currMB->y_4x4_dc[i][j][k][0];
            dc_pred[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][0];
        }
        else      //  4
        {
            dc_diff[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][0]-( currMB->y_dc[i][j-1]>>1 ); //currMB->y_dc[i][j-1];
            dc_pred[INTRA_LEFT] = currMB->y_dc[i][j-1]>>1;//currMB->y_dc[i][j-1];

        }
        if ( !pix_y || ( pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) )
        {
            min_diff = dc_diff[INTRA_LEFT];
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_4x4_dc[i][j][k][m] ) )
            {
                currMB->b4mode[i][j][k][m] = INTRA_LEFT;
                currMB->y_4x4_dc_diff[i][j][k][m] = min_diff;
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_LEFT];
            }
        }
        else if ( img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )
        {
            dc_diff[INTRA_UP]   = UP_MB_DC_DIFF_4x4( i,j,k,m );
            dc_diff[INTRA_NO]   = currMB->y_4x4_dc[i][j][k][m];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b4mode[i][j][k][m] = y;
                }
            }
            currMB->y_4x4_dc_diff[i][j][k][m] = min_diff;
            switch( currMB->b4mode[i][j][k][m] )
            {
            case INTRA_LEFT:
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_LEFT];
                break;
            case INTRA_UP:
                currMB->y_4x4_dc_pred[i][j][k][m] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][j]>>1;//img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][j];
                break;
            }
        }
        break;
    case 2:
    case 8:
    case 10:
        pix_y = img->pix_y+8*i+4*k;
        pix_x = img->pix_x;
        if ( k )    //  2,10
        {
            dc_diff[INTRA_UP] = currMB->y_4x4_dc[i][j][1][m]-currMB->y_4x4_dc[i][j][0][m];
            dc_pred[INTRA_UP] = currMB->y_4x4_dc[i][j][0][m];
        }
        else      //  8
        {
            dc_diff[INTRA_UP] = currMB->y_4x4_dc[i][j][0][m]-( currMB->y_dc[i-1][j]>>1 ); //currMB->y_dc[i-1][j];
            dc_pred[INTRA_UP] = currMB->y_dc[i-1][j]>>1;//currMB->y_dc[i-1][j];

        }
        if ( !pix_x || ( pix_x && img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) )
        {
            min_diff = dc_diff[INTRA_UP];
            if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_4x4_dc[i][j][k][m] ) )
            {
                currMB->b4mode[i][j][k][m] = INTRA_UP;
                currMB->y_4x4_dc_diff[i][j][k][m] = min_diff;
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_UP];
            }
        }
        else if ( img->mb_data[img->curr_mb_nr-1].mb_type==I8MB )
        {
            dc_diff[INTRA_LEFT]   = LEFT_MB_DC_DIFF_4x4( i,j,k,m );
            dc_diff[INTRA_NO]   = currMB->y_4x4_dc[i][j][k][m];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b4mode[i][j][k][m] = y;
                }
            }
            currMB->y_4x4_dc_diff[i][j][k][m] = min_diff;
            switch( currMB->b4mode[i][j][k][m] )
            {
            case INTRA_LEFT:
                currMB->y_4x4_dc_pred[i][j][k][m] = img->mb_data[img->curr_mb_nr-1].y_dc[i][1]>>1;//img->mb_data[img->curr_mb_nr-1].y_dc[i][1];
                break;
            case INTRA_UP:
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_UP];
                break;
            }
        }
        break;
    case 3:
    case 6:
    case 7:
    case 9:
    case 11:
    case 12:
    case 13:
    case 14:
    case 15:
        //b4_idx 3,6,7,9,12,13,11,14,15
        if ( ( !i&&!j&&k&&m )||( !i&&j&&k )||( i&&!j&&m )||( i&j ) ) //3,6,7,9,12,13,11,14,15
        {
            if ( m )    //  3,7,9,13,11,15
            {
                dc_diff[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][1]-currMB->y_4x4_dc[i][j][k][0];
                dc_pred[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][0];
            }
            else      //  6,12,14
            {
                dc_diff[INTRA_LEFT] = currMB->y_4x4_dc[i][j][k][0]-( currMB->y_dc[i][j-1]>>1 ); //currMB->y_dc[i][j-1];
                dc_pred[INTRA_LEFT] = currMB->y_dc[i][j-1]>>1;//currMB->y_dc[i][j-1];
            }
            if ( k )    //  3,11,6,14,7,15
            {
                dc_diff[INTRA_UP] = currMB->y_4x4_dc[i][j][1][m]-currMB->y_4x4_dc[i][j][0][m];
                dc_pred[INTRA_UP] = currMB->y_4x4_dc[i][j][0][m];
            }
            else      //  9,12,13
            {
                dc_diff[INTRA_UP] = currMB->y_4x4_dc[i][j][0][m]-( currMB->y_dc[i-1][j]>>1 );
                dc_pred[INTRA_UP] = currMB->y_dc[i-1][j]>>1;
            }
            dc_diff[INTRA_NO] = currMB->y_4x4_dc[i][j][k][m];
            min_diff = MAX_VALUE;
            for ( y=0; y<3; y++ )
            {
                if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
                {
                    min_diff = dc_diff[y];
                    currMB->b4mode[i][j][k][m] = y;
                }
            }
            currMB->y_4x4_dc_diff[i][j][k][m] = min_diff;
            switch( currMB->b4mode[i][j][k][m] )
            {
            case INTRA_LEFT:
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_LEFT];
                break;
            case INTRA_UP:
                currMB->y_4x4_dc_pred[i][j][k][m] = dc_pred[INTRA_UP];
                break;
            }
        }
        break;
    }
}
#else
static void decide_y_intra_mode_16()
{
    int y;
    int dc_diff[3], min_diff;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];


    memcpy( img->b16_residual[0],&img->y_residual[0][0],256*sizeof( int ) );
    transform_B16( img->b16_residual );
    quant_B16( img->vbs_qp_16x16, currMB->mb_type==5?4:0, img->b16_residual );

    currMB->y_16x16_dc = img->b16_residual[0][0];
    currMB->y_16x16_dc_diff = currMB->y_16x16_dc;
    currMB->y_16x16_dc_pred = 0;

    if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        currMB->b16mode = INTRA_NO;
    }
    else if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        min_diff = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_16x16_dc ) ) //select <= to prefer to the small mode
        {
            //the following is the same reason
            currMB->b16mode = INTRA_LEFT;
            currMB->y_16x16_dc_diff = min_diff;
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        }
    }
    else if( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        min_diff = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        if ( RFM_ABS( min_diff ) <= RFM_ABS( currMB->y_16x16_dc ) )
        {
            currMB->b16mode = INTRA_UP;
            currMB->y_16x16_dc_diff = min_diff;
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        }
    }
    else if ( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )&& ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        dc_diff[INTRA_LEFT] = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        dc_diff[INTRA_UP]   = currMB->y_16x16_dc-img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        dc_diff[INTRA_NO]   = currMB->y_16x16_dc;
        min_diff = MAX_VALUE;
        for ( y=0; y<3; y++ )
        {
            if ( RFM_ABS( dc_diff[y] ) < RFM_ABS( min_diff ) )
            {
                min_diff = dc_diff[y];
                currMB->b16mode = y;
            }
        }
        currMB->y_16x16_dc_diff = min_diff;
        switch( currMB->b16mode )
        {
        case INTRA_LEFT:
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
            break;
        case INTRA_UP:
            currMB->y_16x16_dc_pred = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
            break;
        }
    }
}

void decide_y_intra_b8_mode( int block8x8 )
{
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];

#define LEFT_MB_DC_DIFF(y,x) (currMB->y_dc[y][0] - img->mb_data[img->curr_mb_nr-1].y_dc[y][1])
#define UP_MB_DC_DIFF(y,x)   (currMB->y_dc[0][x] - img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][x])
#define LEFT_B8_DC_DIFF(y,x) (currMB->y_dc[y][1] - currMB->y_dc[y][0])
#define UP_B8_DC_DIFF(y,x)   (currMB->y_dc[1][x] - currMB->y_dc[0][x])

    switch ( block8x8 )
    {
    case 0:
        if ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB )
        {
            currMB->b8mode[0][0]    = INTRA_LEFT;
            currMB->y_dc_diff[0][0] = LEFT_MB_DC_DIFF( 0,0 );
            currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1];
        }
        else if( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )
        {
            currMB->b8mode[0][0]    = INTRA_UP;
            currMB->y_dc_diff[0][0] = UP_MB_DC_DIFF( 0,0 );
            currMB->y_dc_pred[0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0];
        }
		else
		{
			currMB->b8mode[0][0]    = INTRA_NO;
		}
        break;
    case 1:
        currMB->b8mode[0][1]    = INTRA_LEFT;
        currMB->y_dc_diff[0][1] = LEFT_B8_DC_DIFF( 0,1 );
        currMB->y_dc_pred[0][1] = currMB->y_dc[0][0];

        break;
    case 2:
        currMB->b8mode[1][0]    = INTRA_UP;
        currMB->y_dc_diff[1][0] = UP_B8_DC_DIFF( 1,0 );
        currMB->y_dc_pred[1][0] = currMB->y_dc[0][0];

        break;
    case 3:
        currMB->b8mode[1][1]    = INTRA_LEFT;
        currMB->y_dc_diff[1][1] = LEFT_B8_DC_DIFF( 1,1 );
        currMB->y_dc_pred[1][1] = currMB->y_dc[1][0];
        break;
    }
}

void decide_y_intra_b4_mode(int block4x4)
{
	int i,j,k,m;
	macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];

#define LEFT_MB_DC_DIFF_4x4(i,j,k,m) (currMB->y_4x4_dc[i][0][k][0] - (img->mb_data[img->curr_mb_nr-1].y_dc[i][1]>>1))
#define UP_MB_DC_DIFF_4x4(i,j,k,m)   (currMB->y_4x4_dc[0][j][0][m] - (img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][j]>>1))

	i = block4x4/8;
	j = (block4x4-8*i)/4;
	k = (block4x4-8*i-4*j)/2;
	m = block4x4-8*i-4*j-2*k;
	switch (block4x4)
	{
	case 0:
		if ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB )
		{
			currMB->b4mode[0][0][0][0]        = INTRA_LEFT;
			currMB->y_4x4_dc_diff[0][0][0][0] = LEFT_MB_DC_DIFF_4x4(0,0,0,0);
			currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-1].y_dc[0][1]>>1;
		}
		else if( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )
		{
			currMB->b4mode[0][0][0][0]        = INTRA_UP;
			currMB->y_4x4_dc_diff[0][0][0][0] = UP_MB_DC_DIFF_4x4(0,0,0,0);
			currMB->y_4x4_dc_pred[0][0][0][0] = img->mb_data[img->curr_mb_nr-img->mb_width].y_dc[1][0]>>1;
		}
		else
		{
			currMB->b4mode[0][0][0][0]        = INTRA_NO;
		}
		break;

	case 1:
	case 2:
	case 3:
	case 5:
	case 6:
	case 7:
	case 9:
	case 10:
	case 11:
	case 13:
	case 14:
	case 15:
		currMB->y_4x4_dc_diff[i][j][k][m] = currMB->y_4x4_dc[i][j][k][m]-currMB->y_4x4_dc[i][j][0][0];
		currMB->y_4x4_dc_pred[i][j][k][m] = currMB->y_4x4_dc[i][j][0][0];
		break;
	case 4:
	case 8:
	case 12:
		currMB->y_4x4_dc_diff[i][j][k][m] = currMB->y_4x4_dc[i][j][k][m] - (currMB->y_dc[0][0]>>1);
		currMB->y_4x4_dc_pred[i][j][k][m] = currMB->y_dc[0][0]>>1;
		break;
	}
}
#endif
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int intra_luma_residual_coding( int trans_index )
{
    int rate=0;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    get_residual( I8MB, img->org_y_data, intra_pred, img->y_residual );
    switch( trans_index )
    {
    case TRANS16:
        decide_y_intra_mode_16();    //To be added
        rate = y_coding16( currMB );
        break;
    case TRANS8:
        rate = y_coding8in4( currMB );
        break;
    case NON_ABT:
        rate = y_coding( currMB );
        break;
    }

    return rate;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
#if INTRA_MODE_ADAPTIVE_CHROMA
static void decide_uv_intra_mode()
{
    int uv, mode;
    int dc_diff[3], min_diff;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
#define LEFT_MB_UV_DC_DIFF (RFM_ABS(currMB->uv_dc[0] - img->mb_data[img->curr_mb_nr-1].uv_dc[0])+RFM_ABS(currMB->uv_dc[1] - img->mb_data[img->curr_mb_nr-1].uv_dc[1]))
#define UP_MB_UV_DC_DIFF   (RFM_ABS(currMB->uv_dc[0] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[0])+RFM_ABS(currMB->uv_dc[1] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[1]))
#define CURR_MB_UV_DC      (RFM_ABS(currMB->uv_dc[0]) + RFM_ABS(currMB->uv_dc[1]))
    for ( uv=0; uv<UV; uv++ )
    {
        get_residual( UV_MODE, img->org_uv_data[uv], intra_pred, img->uv_residual[uv] );
        transform_b8( img->uv_residual[uv] );
        //  quant_b8(currMB->qp_chroma /*qp*//*//ChomaQP [9/17/2011 Will] */ , 1, img->uv_residual[uv],uv+1);
        quant_b8( currMB->qp_chroma, 1, img->uv_residual[uv] );    //liwr

        //if(input->AdaptiveRounding)
        //  set_qadjust_to_best1_uv();
        currMB->uv_dc[uv] = img->uv_residual[uv][0][0];
        currMB->uv_dc_diff[uv] = currMB->uv_dc[uv];
    }
    memset( currMB->uv_dc_pred, 0, 2*sizeof( int ) );
    if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        currMB->uvmode = INTRA_NO;
    }
    else if ( ( !img->pix_y || ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type!=I8MB ) ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        if ( LEFT_MB_UV_DC_DIFF <= CURR_MB_UV_DC ) //select <= to prefer to the small mode
        {
            //the following is the same reason
            currMB->uvmode = INTRA_LEFT;
            for ( uv=0; uv<UV; uv++ )
            {
                currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
                currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
            }
        }
    }
    else if( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( !img->pix_x||( img->pix_x&&img->mb_data[img->curr_mb_nr-1].mb_type!=I8MB ) ) )
    {
        if ( UP_MB_UV_DC_DIFF <= CURR_MB_UV_DC )
        {
            currMB->uvmode = INTRA_UP;
            for ( uv=0; uv<UV; uv++ )
            {
                currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
                currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
            }
        }
    }
    else if ( ( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB ) && ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB ) )
    {
        dc_diff[INTRA_LEFT] = LEFT_MB_UV_DC_DIFF;;
        dc_diff[INTRA_UP]   = UP_MB_UV_DC_DIFF;
        dc_diff[INTRA_NO]   = CURR_MB_UV_DC;
        min_diff = MAX_VALUE;
        for ( mode=0; mode<3; mode++ )
        {
            if ( dc_diff[mode] < min_diff )
            {
                min_diff = dc_diff[mode];
                currMB->uvmode = mode;
            }
        }
        switch( currMB->uvmode )
        {
        case INTRA_LEFT:
            for ( uv=0; uv<UV; uv++ )
            {
                currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
                currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
            }
            break;
        case INTRA_UP:
            for ( uv=0; uv<UV; uv++ )
            {
                currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
                currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
            }
            break;
        }
    }
}

#else
static void decide_uv_intra_mode()
{
	int uv;
	macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];

#define LEFT_MB_UV_DC_DIFF (RFM_ABS(currMB->uv_dc[0] - img->mb_data[img->curr_mb_nr-1].uv_dc[0])+RFM_ABS(currMB->uv_dc[1] - img->mb_data[img->curr_mb_nr-1].uv_dc[1]))
#define UP_MB_UV_DC_DIFF   (RFM_ABS(currMB->uv_dc[0] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[0])+RFM_ABS(currMB->uv_dc[1] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[1]))
#define CURR_MB_UV_DC      (RFM_ABS(currMB->uv_dc[0]) + RFM_ABS(currMB->uv_dc[1]))

	for (uv=0; uv<UV; uv++)
	{
		get_residual(UV_MODE, img->org_uv_data[uv], intra_pred, img->uv_residual[uv]);
		transform_b8(img->uv_residual[uv]);
		quant_b8(currMB->qp_chroma, 1, img->uv_residual[uv]);
		currMB->uv_dc[uv] = img->uv_residual[uv][0][0];
		currMB->uv_dc_diff[uv] = currMB->uv_dc[uv];
	}
	memset(currMB->uv_dc_pred, 0, 2*sizeof(int));

	if ( img->pix_x && img->mb_data[img->curr_mb_nr-1].mb_type==I8MB )
	{
		currMB->uvmode = INTRA_LEFT;
		for (uv=0; uv<UV; uv++)
		{
			currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
			currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-1].uv_dc[uv];
		}
	}
	else if( img->pix_y && img->mb_data[img->curr_mb_nr-img->mb_width].mb_type==I8MB )
	{
		currMB->uvmode = INTRA_UP;
		for (uv=0; uv<UV; uv++)
		{
			currMB->uv_dc_diff[uv] = currMB->uv_dc[uv] - img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
			currMB->uv_dc_pred[uv] = img->mb_data[img->curr_mb_nr-img->mb_width].uv_dc[uv];
		}
	}
	else
	{
		currMB->uvmode = INTRA_NO;
		for (uv=0; uv<UV; uv++)
		{
			currMB->uv_dc_diff[uv] = currMB->uv_dc[uv];
			currMB->uv_dc_pred[uv] = 0;
		}
	}
}
#endif
int intra_chroma_residual_coding()
{
    int rate = 0, uv;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    decide_uv_intra_mode();
#if INTRA_MODE_ADAPTIVE_CHROMA
    write_chroma_intra_mode();
#endif
    for ( uv = 0; uv < UV; uv++ )
    {
        get_residual( UV_MODE, img->org_uv_data[uv], intra_pred, img->uv_residual[uv] );
        rate += uv_coding( currMB,uv );
    }
    if( input->AdaptiveRounding )
        set_qadjust_to_best1_uv();
    return rate;
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void get_inter_pred_y( macroblock_t *currMB )
{
#if QUARTER_PIXEL
    static const int positionQ[4][4] = {{0, 4, 1, 5}, {6, 8, 14, 9}, {2, 12, 3, 13}, {7, 10, 15, 11}};  //dw 20110808
#else
    static const int postion[2][2] = {{0, 1}, {2, 3}};
#endif
    int i, j, ref_idx, pic_y, pic_x, dir, x, y, x_offset[2], y_offset[2];
    int blk4x4_y, blk4x4_x;
    int pred_x, pred_y;
    int mode, pos[2];
    byte **ref_frm[2];
    int dx,dy;

    mv_t mv[2];
    mode = currMB->mb_type ;
    for ( j = 0; j < 2; j++ )
    {
        for ( i = 0; i < 2; i++ )
        {
            pic_y  = img->pix_y + 8 * j;
            pic_x  = img->pix_x + 8 * i;
            pred_y = 8 * j;
            pred_x = 8 * i;

            if( input->ABTen && input->InterABTen && mode == INTER8x8 && currMB->subblock_type[j*2 +i] == SUBBLOCK_INTER4x4 )
            {
                for ( blk4x4_y=0; blk4x4_y<=1; blk4x4_y++ )
                {
                    for ( blk4x4_x=0; blk4x4_x<=1; blk4x4_x++ )
                    {
                        if ( currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x] != BI )
                        {
                            ref_idx = currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x];
                            mv[0]   = img->mv_4x4[ref_idx][2*j+i][2*blk4x4_y+blk4x4_x];
#if QUARTER_PIXEL
                            dy=mv[0].y&3;
                            dx=mv[0].x&3;

                            pos[0]  = positionQ[dy][dx];
#else
                            dy=mv[0].y&1;
                            dx=mv[0].x&1;
                            //pos[0]  = postion[RFM_ABS(mv[0].y) & 1][RFM_ABS(mv[0].x) & 1];
                            pos[0]  = postion[dy][dx];
#endif
                            if ( !pos[0] )
                            {
                                ref_frm[0] = img_y_rec_space[ref_idx];
                            }
                            else
                            {
                                ref_frm[0] = y_up_sampling[ref_idx][pos[0]-1];
                            }
#if QUARTER_PIXEL
                            y_offset[0] = ( mv[0].y-dy )/4 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                            x_offset[0] = ( mv[0].x-dx )/4 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#else
                            y_offset[0] = ( mv[0].y-dy )/2 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                            x_offset[0] = ( mv[0].x-dx )/2 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#endif
                            for ( y = 0; y < B4_SIZE; y++ )
                            {
                                for ( x = 0; x < B4_SIZE; x++ )
                                {
                                    inter_pred[pred_y+blk4x4_y*4+y][pred_x+blk4x4_x*4+x] = ref_frm[0][RFM_CLIP3( y_offset[0] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[0] + x,0,img->p_width-1 )];
                                }
                            }
                        }
                        else
                        {
                            for ( dir = 0; dir < BI; dir++ )
                            {
                                //mv[dir]  = img->mv[dir][mode][j][i];
                                if ( dir==FW )  //
                                    mv[dir] = img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].fw_mv;
                                else          //  BW
                                    mv[dir] = img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].bw_mv;
#if QUARTER_PIXEL
                                dy=mv[dir].y&3;
                                dx=mv[dir].x&3;

                                pos[dir] = positionQ[dy][dx];
#else
                                dy=mv[dir].y&1;
                                dx=mv[dir].x&1;

                                pos[dir] = postion[dy][dx];
#endif
                                if ( !pos[dir] )
                                    ref_frm[dir] = img_y_rec_space[dir];
                                else
                                    ref_frm[dir] = y_up_sampling[dir][pos[dir]-1];

#if QUARTER_PIXEL
                                y_offset[dir] = ( mv[dir].y-dy )/4 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                                x_offset[dir] = ( mv[dir].x-dx )/4 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#else
                                y_offset[dir] = ( mv[dir].y-dy )/2 + pic_y + blk4x4_y*4 + IMG_PAD_SIZE;
                                x_offset[dir] = ( mv[dir].x-dx )/2 + pic_x + blk4x4_x*4 + IMG_PAD_SIZE;
#endif
                            }

                            for ( y = 0; y < B4_SIZE; y++ )
                            {
                                for ( x = 0; x < B4_SIZE; x++ )
                                {
                                    inter_pred[pred_y+blk4x4_y*4+y][pred_x+blk4x4_x*4+x] = ( ref_frm[FW][RFM_CLIP3( y_offset[FW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[FW] + x,0,img->p_width-1 )] + ref_frm[BW][RFM_CLIP3( y_offset[BW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[BW] + x,0,img->p_width-1 )] + 1 )>>1;
                                }
                            }
                        }//end else BI
                    }//end for blk4x4_x
                }//end for blk4x4_y
            }//end vbs_enable
            else
            {
                if ( currMB->b8_ref[j][i] != BI )
                {
                    ref_idx = currMB->b8_ref[j][i];
                    mv[0]   = img->mv[ref_idx][mode][j][i];
#if QUARTER_PIXEL
                    dy=mv[0].y&3;
                    dx=mv[0].x&3;

                    pos[0]  = positionQ[dy][dx];
#else
                    dy=mv[0].y&1;
                    dx=mv[0].x&1;
                    //pos[0]  = postion[RFM_ABS(mv[0].y) & 1][RFM_ABS(mv[0].x) & 1];
                    pos[0]  = postion[dy][dx];
#endif
                    if ( !pos[0] )
                    {
                        ref_frm[0] = img_y_rec_space[ref_idx];
                    }
                    else
                    {
                        ref_frm[0] = y_up_sampling[ref_idx][pos[0]-1];
                    }
#if QUARTER_PIXEL
                    y_offset[0] = ( mv[0].y-dy )/4 + pic_y + IMG_PAD_SIZE;
                    x_offset[0] = ( mv[0].x-dx )/4 + pic_x + IMG_PAD_SIZE;
#else
                    y_offset[0] = ( mv[0].y-dy )/2 + pic_y + IMG_PAD_SIZE;
                    x_offset[0] = ( mv[0].x-dx )/2 + pic_x + IMG_PAD_SIZE;
#endif
                    for ( y = 0; y < B8_SIZE; y++ )
                    {
                        for ( x = 0; x < B8_SIZE; x++ )
                        {
                            inter_pred[pred_y+y][pred_x+x] = ref_frm[0][RFM_CLIP3( y_offset[0] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[0] + x,0,img->p_width-1 )];
                        }
                    }
                }
                else
                {
                    for ( dir = 0; dir < BI; dir++ )
                    {
                        //mv[dir]  = img->mv[dir][mode][j][i];
                        if ( dir==FW )  //
                        {
                            mv[dir] = img->bi_mv[mode][j][i].fw_mv;
                        }
                        else          //  BW
                        {
                            mv[dir] = img->bi_mv[mode][j][i].bw_mv;
                        }
#if QUARTER_PIXEL
                        dy=mv[dir].y&3;
                        dx=mv[dir].x&3;

                        pos[dir] = positionQ[dy][dx];
#else
                        dy=mv[dir].y&1;
                        dx=mv[dir].x&1;

                        pos[dir] = postion[dy][dx];
#endif
                        if ( !pos[dir] )
                        {
                            ref_frm[dir] = img_y_rec_space[dir];
                        }
                        else
                        {
                            ref_frm[dir] = y_up_sampling[dir][pos[dir]-1];
                        }
#if QUARTER_PIXEL
                        y_offset[dir] = ( mv[dir].y-dy )/4 + pic_y + IMG_PAD_SIZE;
                        x_offset[dir] = ( mv[dir].x-dx )/4 + pic_x + IMG_PAD_SIZE;
#else
                        y_offset[dir] = ( mv[dir].y-dy )/2 + pic_y + IMG_PAD_SIZE;
                        x_offset[dir] = ( mv[dir].x-dx )/2 + pic_x + IMG_PAD_SIZE;
#endif
                    }

                    for ( y = 0; y < B8_SIZE; y++ )
                    {
                        for ( x = 0; x < B8_SIZE; x++ )
                        {
                            inter_pred[pred_y+y][pred_x+x] = ( ref_frm[FW][RFM_CLIP3( y_offset[FW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[FW] + x,0,img->p_width-1 )] + ref_frm[BW][RFM_CLIP3( y_offset[BW] + y,0,img->p_height-1 )][RFM_CLIP3( x_offset[BW] + x,0,img->p_width-1 )] + 1 )>>1;
                        }
                    }
                }//end one block
            }//end vbs_enable
        }//end for i
    }//end for j
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void get_inter_pred_uv( macroblock_t *currMB, int uv )
{
    int i, j, ref_idx, pic_y, pic_x, dir, x, y, x_offset[2], y_offset[2];
    int pred_x, pred_y;
    int mode, submode; //xy_110506
    byte **ref_frm[MAX_REF_NUM];
    mv_t mv[2];
    int xh, yh;
    int tmp_pred[2][8][8];
    int blk4x4_y,blk4x4_x;

    for ( j = 0; j < MAX_REF_NUM; j++ )
    {

        ref_frm[j] = img_uv_rec_space_offset[uv][j];
    }

    mode = currMB->mb_type;

    for ( j = 0; j < 2; j++ )
    {
        for ( i = 0; i < 2; i++ )
        {
            pic_y  = img->pix_c_y + 4 * j;
            pic_x  = img->pix_c_x + 4 * i;
            pred_y = 4 * j;
            pred_x = 4 * i;
            submode = currMB->subblock_type[2*j+i]; //xy_110506


            if( input->ABTen && input->InterABTen && submode == SUBBLOCK_INTER4x4 ) //xy_110506
            {
                for ( blk4x4_y=0; blk4x4_y<=1; blk4x4_y++ )
                {
                    for ( blk4x4_x=0; blk4x4_x<=1; blk4x4_x++ )
                    {
                        if ( currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x] != BI )
                        {
                            byte    refpix[4];
                            int     intpix[2];
                            ref_idx = currMB->b4_ref[2*j+i][2*blk4x4_y+blk4x4_x];
                            mv[ref_idx]   = img->mv_4x4[ref_idx][2*j+i][2*blk4x4_y+blk4x4_x];

#if QUARTER_PIXEL
							xh        = mv[ref_idx].x & 7;//hlv, 2012.9.28
							yh        = mv[ref_idx].y & 7;
							mv[ref_idx].x >>= 3;  //  UV half mv
							mv[ref_idx].y >>= 3;  //  UV half mv
#else
                            xh        = mv[ref_idx].x & 3;
                            yh        = mv[ref_idx].y & 3;
                            mv[ref_idx].x >>= 2;  //  UV half mv
                            mv[ref_idx].y >>= 2;  //  UV half mv
#endif
                            x_offset[ref_idx] = mv[ref_idx].x + pic_x + blk4x4_x*2;
                            y_offset[ref_idx] = mv[ref_idx].y + pic_y + blk4x4_y*2;

#define clipx(val) RFM_CLIP3(val,0,img->width_cr-1)
#define clipy(val) RFM_CLIP3(val,0,img->height_cr-1)

                            for ( y = 0; y < 2; y++ )
                            {
                                for ( x = 0; x < 2; x++ )
                                {
                                    refpix[0] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y  )][clipx( x_offset[ref_idx] + x  )];
                                    refpix[1] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y  )][clipx( x_offset[ref_idx] + x+1 )];
                                    refpix[2] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y+1 )][clipx( x_offset[ref_idx] + x  )];
                                    refpix[3] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y+1 )][clipx( x_offset[ref_idx] + x+1 )];

#if QUARTER_PIXEL
                                    intpix[0] = refpix[0]*( 8-xh ) + refpix[1]*xh;
                                    intpix[1] = refpix[2]*( 8-xh ) + refpix[3]*xh;
                                    inter_pred[pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] = ( intpix[0]*( 8-yh ) + intpix[1]*yh + 32 )>>6;
#else
                                    intpix[0] = refpix[0]*( 4-xh ) + refpix[1]*xh;
                                    intpix[1] = refpix[2]*( 4-xh ) + refpix[3]*xh;
                                    inter_pred[pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] = ( intpix[0]*( 4-yh ) + intpix[1]*yh + 8 )>>4;
#endif
                                }
                            }
                        }
                        else
                        {
                            for ( dir = 0; dir < BI; dir++ )
                            {
                                byte    refpix[4];
                                int     intpix[2];
                                mv[dir] = ( dir==FW ) ? img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].fw_mv : img->bi_mv_4x4[2*j+i][2*blk4x4_y+blk4x4_x].bw_mv;
                                ref_frm[dir] = img_uv_rec_space_offset[uv][dir];

#if QUARTER_PIXEL
                                xh        = mv[dir].x & 7;
                                yh        = mv[dir].y & 7;
                                mv[dir].x >>= 3;  //  UV half mv
                                mv[dir].y >>= 3;  //  UV half mv
#else
                                xh        = mv[dir].x & 3;
                                yh        = mv[dir].y & 3;
                                mv[dir].x >>= 2;  //  UV half mv
                                mv[dir].y >>= 2;  //  UV half mv
#endif
                                x_offset[dir] = mv[dir].x + pic_x + blk4x4_x*2;
                                y_offset[dir] = mv[dir].y + pic_y + blk4x4_y*2;

                                for ( y = 0; y < 2; y++ )
                                {
                                    for ( x = 0; x < 2; x++ )
                                    {
                                        refpix[0] = ref_frm[dir][clipy( y_offset[dir] + y  )][clipx( x_offset[dir] + x  )];
                                        refpix[1] = ref_frm[dir][clipy( y_offset[dir] + y  )][clipx( x_offset[dir] + x+1 )];
                                        refpix[2] = ref_frm[dir][clipy( y_offset[dir] + y+1 )][clipx( x_offset[dir] + x  )];
                                        refpix[3] = ref_frm[dir][clipy( y_offset[dir] + y+1 )][clipx( x_offset[dir] + x+1 )];

#if QUARTER_PIXEL
                                        intpix[0] = refpix[0]*( 8-xh ) + refpix[1]*xh;
                                        intpix[1] = refpix[2]*( 8-xh ) + refpix[3]*xh;
                                        tmp_pred[dir][pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] = ( intpix[0]*( 8-yh ) + intpix[1]*yh + 32 )>>6;
#else
                                        intpix[0] = refpix[0]*( 4-xh ) + refpix[1]*xh;
                                        intpix[1] = refpix[2]*( 4-xh ) + refpix[3]*xh;
                                        tmp_pred[dir][pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] = ( intpix[0]*( 4-yh ) + intpix[1]*yh + 8 )>>4;
#endif
                                    }
                                }
                            }
                            //get bi-direction prediction
                            for ( y = 0; y < 2; y++ )
                            {
                                for ( x = 0; x < 2; x++ )
                                {
                                    inter_pred[pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] = ( tmp_pred[FW][pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] + tmp_pred[BW][pred_y+blk4x4_y*2 +y][pred_x+ blk4x4_x*2+x] + 1 ) >> 1;
                                }
                            }
                        }
                    }//emd blk4x4_x
                }//end blk4x4_y
            }//end if inter4x4

            else if( mode == INTER8x8 && ( submode == SUBBLOCK_INTRA4x4 || submode == SUBBLOCK_INTRA8x8 ) )
            {
                for ( y = 0; y < 4; y++ )
                {
                    for ( x = 0; x < 4; x++ )
                    {
                        inter_pred[pred_y+y][pred_x+x] = 128;
                    }
                }
            }

            else
            {
                //not inter4x4
                if ( currMB->b8_ref[j][i] != BI )
                {
                    byte    refpix[4];
                    int     intpix[2];
                    ref_idx = currMB->b8_ref[j][i];
                    mv[ref_idx]   = img->mv[ref_idx][mode][j][i];

#if QUARTER_PIXEL
					xh        = mv[ref_idx].x & 7;
					yh        = mv[ref_idx].y & 7;
					mv[ref_idx].x >>= 3;  //  UV half mv
					mv[ref_idx].y >>= 3;  //  UV half mv
#else
                    xh        = mv[ref_idx].x & 3;
                    yh        = mv[ref_idx].y & 3;
                    mv[ref_idx].x >>= 2;  //  UV half mv
                    mv[ref_idx].y >>= 2;  //  UV half mv
#endif
                    x_offset[ref_idx] = mv[ref_idx].x + pic_x;
                    y_offset[ref_idx] = mv[ref_idx].y + pic_y;

#define clipx(val) RFM_CLIP3(val,0,img->width_cr-1)
#define clipy(val) RFM_CLIP3(val,0,img->height_cr-1)

                    for ( y = 0; y < 4; y++ )
                    {
                        for ( x = 0; x < 4; x++ )
                        {
                            refpix[0] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y  )][clipx( x_offset[ref_idx] + x  )];
                            refpix[1] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y  )][clipx( x_offset[ref_idx] + x+1 )];
                            refpix[2] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y+1 )][clipx( x_offset[ref_idx] + x  )];
                            refpix[3] = ref_frm[ref_idx][clipy( y_offset[ref_idx] + y+1 )][clipx( x_offset[ref_idx] + x+1 )];

#if QUARTER_PIXEL
                            intpix[0] = refpix[0]*( 8-xh ) + refpix[1]*xh;
                            intpix[1] = refpix[2]*( 8-xh ) + refpix[3]*xh;
                            inter_pred[pred_y+y][pred_x+x] = ( intpix[0]*( 8-yh ) + intpix[1]*yh + 32 )>>6;
#else
                            intpix[0] = refpix[0]*( 4-xh ) + refpix[1]*xh;
                            intpix[1] = refpix[2]*( 4-xh ) + refpix[3]*xh;
                            inter_pred[pred_y+y][pred_x+x] = ( intpix[0]*( 4-yh ) + intpix[1]*yh + 8 )>>4;
#endif
                        }
                    }
                }
                else
                {
                    for ( dir = 0; dir < BI; dir++ )
                    {
                        byte    refpix[4];
                        int     intpix[2];
                        mv[dir] = ( dir==FW ) ? img->bi_mv[mode][j][i].fw_mv : img->bi_mv[mode][j][i].bw_mv;
                        ref_frm[dir] = img_uv_rec_space_offset[uv][dir];

#if QUARTER_PIXEL
                        xh        = mv[dir].x & 7;
                        yh        = mv[dir].y & 7;
                        mv[dir].x >>= 3;  //  UV half mv
                        mv[dir].y >>= 3;  //  UV half mv
#else
                        xh        = mv[dir].x & 3;
                        yh        = mv[dir].y & 3;
                        mv[dir].x >>= 2;  //  UV half mv
                        mv[dir].y >>= 2;  //  UV half mv
#endif
                        x_offset[dir] = mv[dir].x + pic_x;
                        y_offset[dir] = mv[dir].y + pic_y;

                        for ( y = 0; y < 4; y++ )
                        {
                            for ( x = 0; x < 4; x++ )
                            {
                                refpix[0] = ref_frm[dir][clipy( y_offset[dir] + y  )][clipx( x_offset[dir] + x  )];
                                refpix[1] = ref_frm[dir][clipy( y_offset[dir] + y  )][clipx( x_offset[dir] + x+1 )];
                                refpix[2] = ref_frm[dir][clipy( y_offset[dir] + y+1 )][clipx( x_offset[dir] + x  )];
                                refpix[3] = ref_frm[dir][clipy( y_offset[dir] + y+1 )][clipx( x_offset[dir] + x+1 )];

#if QUARTER_PIXEL
                                intpix[0] = refpix[0]*( 8-xh ) + refpix[1]*xh;
                                intpix[1] = refpix[2]*( 8-xh ) + refpix[3]*xh;
                                tmp_pred[dir][pred_y+y][pred_x+x] = ( intpix[0]*( 8-yh ) + intpix[1]*yh + 32 )>>6;
#else
                                intpix[0] = refpix[0]*( 4-xh ) + refpix[1]*xh;
                                intpix[1] = refpix[2]*( 4-xh ) + refpix[3]*xh;
                                tmp_pred[dir][pred_y+y][pred_x+x] = ( intpix[0]*( 4-yh ) + intpix[1]*yh + 8 )>>4;
#endif
                            }
                        }
                    }
                    //get bi-direction prediction
                    for ( y = 0; y < 4; y++ )
                    {
                        for ( x = 0; x < 4; x++ )
                        {
                            inter_pred[pred_y+y][pred_x+x] = ( tmp_pred[FW][pred_y+y][pred_x+x] + tmp_pred[BW][pred_y+y][pred_x+x] + 1 ) >> 1;
                        }
                    }
                }
            }
        }//end for i
    }
}



/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int inter_y_residual_coding( int trans_index )
{
    int rate=0;
    int x,y ;

    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    get_inter_pred_y ( currMB );

    for( y=0; y<16; y++ )
    {
        for( x=0; x<16; x++ )
        {
            img->y_residual[y][x] = img->org_y_data[y][x] - inter_pred[y][x] ;
        }
    }


    switch( trans_index )
    {
    case TRANS16:
        rate = y_coding16( currMB );
        break;
        //case TRANS8:
        //  rate = y_coding8in4(currMB);
        //  break;
    case NON_ABT:
        rate = y_coding( currMB );
        break;
        //case TRANS4:
        //  rate = y_coding4(currMB);
        //  break;
    }
    return rate;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int inter_uv_residual_coding()
{
    int rate = 0, uv;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    memset( &inter_pred[0][0], 0, 256*sizeof( byte ) );
    for ( uv = 0; uv < UV; uv++ )
    {
        get_inter_pred_uv ( currMB, uv );
        get_residual      ( UV_MODE, img->org_uv_data[uv], inter_pred, img->uv_residual[uv] );
        if( 1 )   //RDO for 8x8 all 0 coeff, check if all 0 is better
        {
            prob_context_t eob_ctx = qcoder->cx_eob_flag_chroma[0];
            int lps_interval = eob_ctx.prob_fsm[eob_ctx.state].lps_interval;
            int interval = qcoder -> interval;
            int mps_interval = interval - lps_interval;
            int mps = eob_ctx.mps;
            int d8_all0 = 0;
            double rate8_all0, cost8_all0;
            double cost8;
            int x,y;
            int d8=0;
            int rate8;

            if ( ( mps && lps_interval<mps_interval ) || ( !mps && lps_interval>mps_interval ) )
            {
                rate8_all0 = log( ( double )interval/( double )mps_interval ) / log( 2.0 );
            }
            else
            {
                rate8_all0 = log( ( double )interval/( double )lps_interval ) / log( 2.0 );
            }
            //  get distortion 8x8 all0
            for ( y = 0; y < B8_SIZE; y++ )
            {
                for ( x = 0; x < B8_SIZE; x++ )
                {
                    d8_all0 += img->quad[img->uv_residual[uv][y][x]];
                }
            }
            cost8_all0 = d8_all0 + img->lambda_mode * ( rate8_all0 );
            rate8 = uv_coding( currMB,uv );
            //  get distortion 8x8
            for ( y = 0; y < B8_SIZE; y++ )
            {
                int j = img->pix_c_y + y;
                for ( x = 0; x < B8_SIZE; x++ )
                {
                    int i = img->pix_c_x + x;
                    d8 += img->quad[img_uv_org[uv][j][i] - p_img_uv_rec[uv][j][i]];
                }
            }
            cost8 = d8 + img->lambda_mode * ( rate8 );
            if ( cost8_all0 < cost8 )
            {
                for ( y = 0; y < B8_SIZE; y++ )
                {
                    for ( x = 0; x < B8_SIZE; x++ )
                    {
                        p_img_uv_rec[uv][img->pix_c_y+y][img->pix_c_x+x] = inter_pred[y][x];
                    }
                }
                img->cofAC[uv+4][0][0][0] = 0;
                rate8 = write_chroma_coeff_b8_qcoder( uv+4 );
            }
            rate += rate8;
        }
        else
        {
            rate += uv_coding( currMB,uv );
        }
    }
    if( input->AdaptiveRounding )
        set_qadjust_to_best1_uv();
    return rate;
}

static void next_macroblock()
{
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    int *bit_count       = currMB->bit_counter;

    int i,j;
#if TRACE
    if ( trace_out )
    {
        int i;
        if ( p_trace )
        {
            fprintf( p_trace, "\n*********** Pic: %i (I/P) MB: %i Slice: %i **********\n\n", img->tr, img->curr_mb_nr, img->curr_slice_nr );
            for ( i = 0; i < currMB->curr_se_nr; i++ )
                trace2out( &( img->mb_syntax_elements[i] ) );
        }
    }
#endif

    stat->bit_use_mb_type[img->type]     += bit_count[BITS_MB_MODE];
    stat->bit_use_coeff_y[img->type]     += bit_count[BITS_COEFF_Y_MB];
    stat->bit_use_cbp[img->type]         += bit_count[BITS_CBP_MB];
    stat->bit_use_coeff_c[img->type]     += bit_count[BITS_COEFF_UV_MB];
    stat->bit_use_delta_quant[img->type] += bit_count[BITS_DELTA_QUANT_MB];

    if ( img->type == I_IMG )
    {
        ++stat->mode_use_intra[currMB->mb_type];
        ++stat->mode_use_intra[ currMB->subblock_type[0] ];
        ++stat->mode_use_intra[ currMB->subblock_type[1] ];
        ++stat->mode_use_intra[ currMB->subblock_type[2] ];
        ++stat->mode_use_intra[ currMB->subblock_type[3] ];
    }
    else if ( img->type != B_IMG )
    {
        if ( currMB->mb_type == SKIP )
        {
            ++stat->mode_use_inter_changed[0][STAT_SKIP];
        }
        else if ( currMB->mb_type == INTER16x16 )
        {
            ++stat->mode_use_inter_changed[0][STAT_INTER16X16];
            ++stat->pred_direction_use[0][0][FW];
        }
        else                    // INTER8x8
        {
            for ( i=0; i<4; i++ )
            {
                switch ( currMB->subblock_type[i] )
                {
                case SUBBLOCK_INTER8x8:
                    ++stat->mode_use_inter_changed[0][STAT_INTER8X8];
                    ++stat->pred_direction_use[0][1][FW];
                    break;
                case SUBBLOCK_INTRA8x8:
                    ++stat->mode_use_inter_changed[0][STAT_INTRA8X8];
                    ++stat->pred_direction_use[0][1][INTRA];
                    break;
                case SUBBLOCK_INTER4x4:
                    ++stat->mode_use_inter_changed[0][STAT_INTER4X4];
                    for ( j=0; j<4; j++ )
                    {
                        ++stat->pred_direction_use[0][2][FW];
                    }
                    break;
                case SUBBLOCK_INTRA4x4:         // would be omitted in the future
                    ++stat->mode_use_inter_changed[0][STAT_INTRA4X4];
                    stat->pred_direction_use[0][2][INTRA]+=4;
                    break;
                default:
                    break;
                }
            }
        }

        //++stat->mode_use_inter[0][currMB->mb_type];
        stat->bit_use_mode_inter[0][currMB->mb_type] += bit_count[BITS_INTER_MB];
    }
    else
    {
        if ( currMB->mb_type == SKIP )
        {
            ++stat->mode_use_inter_changed[1][STAT_SKIP];
        }
        else if ( currMB->mb_type == INTER16x16 )
        {
            ++stat->mode_use_inter_changed[1][STAT_INTER16X16];
            ++stat->pred_direction_use[1][0][currMB->b8_ref[0][0]];
        }
        else                    // INTER8x8
        {
            for ( i=0; i<4; i++ )
            {
                switch ( currMB->subblock_type[i] )
                {
                case SUBBLOCK_INTER8x8:
                    ++stat->mode_use_inter_changed[1][STAT_INTER8X8];
                    ++stat->pred_direction_use[1][1][currMB->b8_ref[i/2][i%2]];
                    break;
                case SUBBLOCK_INTRA8x8:
                    ++stat->mode_use_inter_changed[1][STAT_INTRA8X8];
                    ++stat->pred_direction_use[1][1][INTRA];
                    break;
                case SUBBLOCK_INTER4x4:
                    ++stat->mode_use_inter_changed[1][STAT_INTER4X4];
                    for ( j=0; j<4; j++ )
                    {
                        ++stat->pred_direction_use[1][2][currMB->b4_ref[i][j]];
                    }
                    break;
                case SUBBLOCK_INTRA4x4:
                    ++stat->mode_use_inter_changed[1][STAT_INTRA4X4];
                    stat->pred_direction_use[1][2][INTRA]+=4;
                    break;
                default:
                    break;
                }
            }
        }
        stat->bit_use_mode_inter[1][currMB->mb_type] += bit_count[BITS_INTER_MB];
        //++stat->mode_use_inter[1][currMB->mb_type];
    }
}

static void terminate_macroblock()
{
    int slice_mb              = input->slice_row_nr * img->mb_width;

    img->coded_mb_nr++;
    if ( input->slice_row_nr && ( img->coded_mb_nr != img->total_mb_num ) )
    {
        if ( img->coded_mb_nr % slice_mb == 0 )
        {
            img->mb_data[img->curr_mb_nr + 1].slice_nr = img->mb_data[img->curr_mb_nr].slice_nr + 1;
            img->mb_no_currSliceLastMB                 = RFM_MIN( img->mb_no_currSliceLastMB + slice_mb, img->total_mb_num );
        }
        else
            img->mb_data[img->curr_mb_nr + 1].slice_nr = img->mb_data[img->curr_mb_nr].slice_nr;
    }

    if ( img->coded_mb_nr == img->total_mb_num )
    {
        img->coded_mb_nr = 0;
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int write_luma_coeff_b16_qcoder( int intra )
{
    int no_bits        = 0;
    int mb_nr          = img->curr_mb_nr;
    macroblock_t *currMB = &img->mb_data[mb_nr];
    const int cbp      = currMB->cbp_16x16;
    int *bitCount      = currMB->bit_counter;
    int inumcoeff;                  /* number of coeffs per block */
    int iblk;                       /* current block */
    int icoef;                      /* current coefficient */
    int ipos;                       /* current position in cof */
    int i, j;

    int coeff[256];
    int coeff_ptr = 0;
    int pos = 0;
    int  eobflag = 0;
    int code_len = 0;

    //static const int blkmode2ctx [4] = {LUMA_8x8, LUMA_8x4, LUMA_4x8, LUMA_4x4};
    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 256*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;
    inumcoeff = 256;

    if ( cbp&1 )
    {
        //code all symbols
        for ( iblk=0; iblk<1; iblk++ )
        {
            i=0;        // =b4
            j=( i&~1 )<<1; //off_x
            i=( i&1 )<<2; //off_y
            if( ( i<0 ) || ( i>=8 ) || ( j<0 ) || ( j>=8 ) )
                continue;        //used in Intra RDopt. code one one subblock.

            ipos  = 0;

            for( icoef=0; icoef<inumcoeff; icoef++ )
            {
                if( !img->cofAC16x16[icoef][0] )
                    break;
                pos += img->cofAC16x16[icoef][1];
                coeff[pos++] = img->cofAC16x16[icoef][0];
                coeff_ptr++;
            }

            for( ipos=0; ipos<pos; )
            {
                code_len = qcoder_encode_eobflag( qcoder, eobflag );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;

                if( !eobflag )
                {
                    do
                    {
                        code_len = qcoder_encode_luma_16x16_coeff( qcoder, ipos, coeff[ipos], isintra );
                        no_bits += code_len;
                        bitCount[BITS_COEFF_Y_MB] += code_len;
                        ipos++;
                    }
                    while( coeff[ipos-1]==0 );
                }
            }

            if( ipos != 256 )
            {
                eobflag = 1;
                code_len = qcoder_encode_eobflag( qcoder, eobflag );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;
            }
        }//loop for iblk
    }
    return no_bits;
}

#ifdef RDO_Q
int est_luma_coeff_b16_qcoder( int intra )
{
    int no_bits        = 0;
    int mb_nr          = img->curr_mb_nr;
    macroblock_t *currMB = &img->mb_data[mb_nr];
    int cbp = 0 ;
    int *bitCount      = currMB->bit_counter;

    int inumcoeff;                  /* number of coeffs per block */
    int iblk;                       /* current block */
    int icoef;                      /* current coefficient */
    int ipos;                       /* current position in cof */
    int i, j;

    int coeff[256];
    int coeff_ptr = 0;
    int pos = 0;
    int  eobflag = 0;
    int code_len = 0;

    int isintra = ( currMB->mb_type==I8MB||currMB->mb_type==I4MB );

    memset( coeff, 0, 256*sizeof( int ) );
    pos = 0;
    coeff_ptr = 0;
    inumcoeff = 256;

    for( icoef=0; icoef<inumcoeff; icoef++ )
    {
        if( img->cofAC16x16[icoef][0] )
        {
            cbp = 1;
            break;
        }
    }

    if ( cbp )
    {
        //code all symbols
        for ( iblk=0; iblk<1; iblk++ )
        {
            i=0;        // =b4
            j=( i&~1 )<<1; //off_x
            i=( i&1 )<<2; //off_y
            if( ( i<0 ) || ( i>=8 ) || ( j<0 ) || ( j>=8 ) )
                continue;        //used in Intra RDopt. code one one subblock.

            ipos  = 0;

            for( icoef=0; icoef<inumcoeff; icoef++ )
            {
                if( !img->cofAC16x16[icoef][0] )
                    break;
                pos += img->cofAC16x16[icoef][1];
                coeff[pos++] = img->cofAC16x16[icoef][0];
                coeff_ptr++;
            }

            for( ipos=0; ipos<pos; )
            {
                code_len = qcoder_encode_eobflag( qcoder, eobflag );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;

                if( !eobflag )
                {
                    do
                    {
                        code_len = qcoder_encode_luma_16x16_coeff( qcoder, ipos, coeff[ipos], isintra );
                        no_bits += code_len;
                        bitCount[BITS_COEFF_Y_MB] += code_len;
                        ipos++;
                    }
                    while( coeff[ipos-1]==0 );
                }
            }

            if( ipos != 256 )
            {
                eobflag = 1;
                code_len = qcoder_encode_eobflag( qcoder, eobflag );
                no_bits += code_len;
                bitCount[BITS_COEFF_Y_MB] += code_len;
            }
        }//loop for iblk
    }
    return no_bits;
}

#endif


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void set_mb_para( int mb )
{
    img->curr_mb_nr = mb;
    img->mb_y       = mb / img->mb_width;
    img->block8_y   = img->mb_y * 2/*B8_SIZE*/;
    img->pix_y      = img->mb_y * MB_BLOCK_SIZE;
    img->pix_c_y    = img->mb_y * ( MB_BLOCK_SIZE >> 1 );
    img->mb_x       = mb % img->mb_width;
    img->block8_x   = img->mb_x * 2/*B8_SIZE*/;
    img->pix_x      = img->mb_x * MB_BLOCK_SIZE;
    img->pix_c_x    = img->mb_x * ( MB_BLOCK_SIZE >> 1 );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void start_macroblock()
{
    static const bi_mv_t invalid_bi_mv = {{0, 0, -1}, {0, 0, -1}};
    static const mv_t invalid_mv = {0, 0, -1};
    int i, j;
    macroblock_t *currMB = &img->mb_data[img->curr_mb_nr];
    img->curr_slice_nr   = img->mb_data[img->curr_mb_nr].slice_nr;
    currMB->slice_nr     = img->curr_slice_nr;

    //load the original data
    for ( j=0; j<MB_BLOCK_SIZE; j++ )
    {
        memcpy( img->org_y_data[j], &img_y_org[img->pix_y+j][img->pix_x], MB_BLOCK_SIZE*sizeof( byte ) );
    }
    for ( i=0; i<UV; i++ )
    {
        for ( j=0; j<B8_SIZE; j++ )
        {
            memcpy( img->org_uv_data[i][j], &img_uv_org[i][img->pix_c_y+j][img->pix_c_x], B8_SIZE*sizeof( byte ) );
        }
    }

    if ( input->rc_enable )
    {
        if ( input->basic_unit == img->total_mb_num )
        {
            currMB->delta_qp = 0;
            currMB->qp       = img->qp;
        }
        else
        {
            if ( ( img->type == I_IMG ) || ( img->type == B_IMG ) )
            {
                currMB->delta_qp = 0;
                currMB->qp       = img->qp;
            }
            else if ( img->type == P_IMG )
            {
                if ( img->curr_mb_nr == 0 )
                {
                    currMB->delta_qp = 0;
                    currMB->qp       = img->qp;
                    DELTA_QP         = DELTA_QP2 = currMB->delta_qp;
                    QP               = QP2       = currMB->qp;
                }
                else if ( input->slice_row_nr && ( img->curr_mb_nr > 0 && img->mb_data[img->curr_mb_nr].slice_nr != img->mb_data[img->curr_mb_nr - 1].slice_nr ) )
                {
                    currMB->delta_qp = 0;
                    currMB->qp       = img->qp;
                    DELTA_QP         = DELTA_QP2 = currMB->delta_qp;
                    QP               = QP2       = currMB->qp;
                }
                else
                {
                    if ( img->mb_data[img->curr_mb_nr - 1].prev_cbp == 1 )
                    {
                        currMB->delta_qp = 0;
                        currMB->qp       = img->qp;
                    }
                    else
                    {
                        currMB->qp       = img->mb_data[img->curr_mb_nr - 1].prev_qp;
                        currMB->delta_qp = currMB->qp - img->mb_data[img->curr_mb_nr - 1].qp;
                        img->qp          = currMB->qp;
                    }
                    DELTA_QP = DELTA_QP2 = currMB->delta_qp;
                    QP = QP2 = currMB->qp;
                }
                if ( ( img->coded_mb > 0 ) && ( img->coded_mb % img->basic_unit == 0 ) )
                {
                    update_rc_model();
                    img->BasicUnitQP = update_quant_para( 0 );
                }

                if ( img->curr_mb_nr == 0 )
                    img->BasicUnitQP = img->qp;

                currMB->predict_qp = img->BasicUnitQP;

                if ( currMB->predict_qp > currMB->qp + 25 )
                    currMB->predict_qp = currMB->qp + 25;
                else if ( currMB->predict_qp < currMB->qp - 26 )
                    currMB->predict_qp = currMB->qp - 26;

                currMB->prev_qp = currMB->predict_qp;

                dq = currMB->delta_qp + currMB->predict_qp - currMB->qp;
                if ( dq < -26 )
                {
                    dq               = -26;
                    predict_error    = dq - currMB->delta_qp;
                    img->qp          = img->qp + predict_error;
                    currMB->delta_qp = -26;
                }
                else if ( dq > 25 )
                {
                    dq               = 25;
                    predict_error    = dq - currMB->delta_qp;
                    img->qp          = img->qp + predict_error;
                    currMB->delta_qp = 25;
                }
                else
                {
                    currMB->delta_qp = dq;
                    predict_error    = currMB->predict_qp - currMB->qp;
                    img->qp          = currMB->predict_qp;
                }
                currMB->qp            = img->qp;
                currMB->predict_error = predict_error;
            }
        }
    }
    else
    {
        currMB->delta_qp = 0;
        currMB->qp       = img->qp;
    }
    if ( img->type == P_IMG )
    {
        for ( j = 0; j < 2; j++ )
            for ( i = 0; i < 2; i++ )
            {
                frm_mv[MAX_REF_NUM][img->block8_y+j][img->block8_x+i] = invalid_mv;
            }
    }
    else if ( img->type == B_IMG )
    {
        for ( j = 0; j < 2; j++ )
            for ( i = 0; i < 2; i++ )
            {
                frm_bi_mv[img->block8_y+j][img->block8_x+i] = invalid_bi_mv;
            }
    }

    currMB->qp_chroma  = QP_SCALE_CR[currMB->qp];
    currMB->curr_se_nr = 0;
    currMB->mb_type    = 0;
    currMB->cbp        = 0;
    currMB->transform_16x16 = 0;
    currMB->cbp_16x16 = 0;
    for ( i=0; i<4; i++ )
    {
        currMB->transform_4x4[i] = 0;
        currMB->cbp_4x4[i] = 0;
        currMB->subblock_type[i] = 0;
    }

    memset( currMB->mvd, 0, 2*2*sizeof( mvd_t ) );
    memset( currMB->mvd_4x4, 0, 4*4*sizeof( mvd_t ) );

    if ( img->curr_mb_nr == 0 )
    {
        currMB->bit_counter[BITS_HEADER] = 0;
    }
    else if ( currMB->slice_nr == img->mb_data[img->curr_mb_nr - 1].slice_nr )
    {
        currMB->bit_counter[BITS_HEADER] = 0;
    }
    currMB->bit_counter[BITS_MB_MODE]        = 0;
    currMB->bit_counter[BITS_COEFF_Y_MB]     = 0;
    currMB->bit_counter[BITS_INTER_MB]       = 0;
    currMB->bit_counter[BITS_CBP_MB]         = 0;
    currMB->bit_counter[BITS_DELTA_QUANT_MB] = 0;
    currMB->bit_counter[BITS_COEFF_UV_MB]    = 0;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void allocate_tmp_bitstream()
{
    const int buffer_size = ( img->width * img->height * 4 );

    if ( ( tmp_stream = ( bitstream_t * ) calloc( 1, sizeof( bitstream_t ) ) ) == NULL )
        no_mem_exit( "malloc_slice: bitstream_t" );
    if ( ( tmp_stream->stream_buffer = ( byte * ) calloc( buffer_size, sizeof( byte ) ) ) == NULL )
        no_mem_exit( "malloc_slice: StreamBuffer" );

    tmp_stream->bits_to_go = 8;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void free_tmp_bitstream()
{
    if ( tmp_stream->stream_buffer )
        free( tmp_stream->stream_buffer );
    if ( tmp_stream )
        free( tmp_stream );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void demulate( bitstream_t * curr_stream, int curr_slice_byte_pos )
{
    int i, j;
    uint32_t rawbitsequence = -1;
    int bitvalue, nonzero, bitnum;
    if ( !( curr_stream->stream_buffer[curr_slice_byte_pos] == 0 && curr_stream->stream_buffer[curr_slice_byte_pos + 1] == 0 && curr_stream->stream_buffer[curr_slice_byte_pos + 2] == 1 ) )
        printf( "Fatal bitstream error" );
    allocate_tmp_bitstream();
    bitnum                = 8;
    tmp_stream->bits_to_go = 0;
    curr_stream->stream_buffer[curr_stream->byte_pos] = curr_stream->byte_buf << curr_stream->bits_to_go;

    for ( tmp_stream->byte_pos = i = curr_slice_byte_pos + 3; i <= curr_stream->byte_pos; i++ )
    {
        for ( j = 8; j > ( i == curr_stream->byte_pos ? curr_stream->bits_to_go : 0 ); j-- )
        {
            bitvalue = curr_stream->stream_buffer[i] & ( 0x01 << ( j - 1 ) );
            if ( bitnum == 2 )
            {
                nonzero = rawbitsequence & 0x003fffff;
                if ( !nonzero )
                {
                    tmp_stream->stream_buffer[tmp_stream->byte_pos] = 0x02;
                    tmp_stream->byte_pos++;
                    tmp_stream->bits_to_go += 2;
                    rawbitsequence = 0x00000002;
                    bitnum = 8;
                }
            }

            rawbitsequence <<= 1;
            if ( bitvalue )
            {
                tmp_stream->stream_buffer[tmp_stream->byte_pos] |= 1 << ( bitnum - 1 );
                rawbitsequence |= 1;
            }
            else
            {
                tmp_stream->stream_buffer[tmp_stream->byte_pos] &= ( ~( 1 << ( bitnum - 1 ) ) );
            }
            bitnum--;
            tmp_stream->bits_to_go++;
            if ( bitnum == 0 )
            {
                bitnum = 8;
                tmp_stream->byte_pos++;
            }
        }
    }
    for ( i = curr_slice_byte_pos + 3; i <= tmp_stream->byte_pos; i++ )
    {
        curr_stream->stream_buffer[i] = tmp_stream->stream_buffer[i];
    }

    curr_stream->byte_pos = tmp_stream->byte_pos;
    curr_stream->bits_to_go = 8 - tmp_stream->bits_to_go % 8;
    curr_stream->byte_buf = tmp_stream->stream_buffer[tmp_stream->byte_pos] >> curr_stream->bits_to_go;
    free_tmp_bitstream();
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int start_slice()
{
    if ( 1 /*img->picture_structure*/ && img->curr_mb_nr != 0 )
        demulate( curr_stream, curr_slice_byte_pos );

    if ( curr_stream->bits_to_go != 8 )
    {
        curr_stream->byte_buf <<= curr_stream->bits_to_go;
        curr_stream->byte_buf  |= ( 1 << ( curr_stream->bits_to_go - 1 ) );
        curr_stream->stream_buffer[curr_stream->byte_pos++] = curr_stream->byte_buf;
        curr_stream->bits_to_go = 8;
        curr_stream->byte_buf   = 0;
    }
    else
    {
        curr_stream->stream_buffer[curr_stream->byte_pos++] = 0x80;
        curr_stream->bits_to_go = 8;
        curr_stream->byte_buf   = 0;
    }
    curr_slice_byte_pos = curr_stream->byte_pos;
    return 0;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int terminate_pic()
{
    demulate( curr_stream, curr_slice_byte_pos );
    curr_stream->byte_buf                                <<= curr_stream->bits_to_go;
    curr_stream->byte_buf                                 |= ( 1 << ( curr_stream->bits_to_go - 1 ) );
    curr_stream->stream_buffer[curr_stream->byte_pos++] = curr_stream->byte_buf;
    curr_stream->bits_to_go                                = 8;
    curr_stream->byte_buf                                  = 0;
    return 0;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void get_lambda_value()
{
    int qp;
    static const int QP2QUANT[40] =
    {
        1  , 1  , 1  , 1  , 2  , 2  , 2  , 2  ,
        3  , 3  , 3  , 4  , 4  , 4  , 5  , 6  ,
        6  , 7  , 8  , 9  , 10 , 11 , 13 , 14 ,
        16 , 18 , 20 , 23 , 25 , 29 , 32 , 36 ,
        40 , 45 , 51 , 57 , 64 , 72 , 81 , 91
    };

    if ( input->rdopt )
    {
        qp = ( double )img->qp - SHIFT_QP;
        if ( input->succe_b > 0 )
            img->lambda_mode = 0.68 * pow( 2, qp / 4.0 ) * ( img->type == B_IMG ? RFM_MAX( 2.00, RFM_MIN( 4.00, ( qp / 8.0 ) ) ) : 1.0 );
        else
            img->lambda_mode = 0.85 * pow( 2, qp / 4.0 ) * ( img->type == B_IMG ? 4.0 : 1.0 );

        img->lambda_motion = sqrt( img->lambda_mode );
    }
    else
    {
        img->lambda_mode = img->lambda_motion = QP2QUANT[RFM_MAX( 0, ( int )( ( float )( img->qp - SHIFT_QP ) * 0.75 + 0.5 ) )];
    }
    img->lambda_motion_factor = LAMBDA_FACTOR( img->lambda_motion );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void pic_data()
{
    int curr_mb_nr = 0;
    int slice_nr   = 0;
    int intra      = ( img->type == I_IMG );
    static int first_slice = 1;

    first_slice = 1;
    get_lambda_value();
    if( img->type>0 )
        intra_num[img->type-1] = 0;
    while ( curr_mb_nr < img->total_mb_num )
    {
        set_mb_para( curr_mb_nr );
        if ( input->slice_row_nr && ( img->curr_mb_nr == 0 || ( img->curr_mb_nr > 0 && img->mb_data[img->curr_mb_nr].slice_nr != img->mb_data[img->curr_mb_nr - 1].slice_nr ) ) )
        {
            start_slice();
            img->curr_slice_qp       = img->qp;
            img->curr_slice_start_mb = img->curr_mb_nr;
            stat->bit_slice         += slice_header( slice_nr, img->curr_slice_qp );
            slice_nr++;
            if( first_slice )
            {
                qcoder_init( qcoder, curr_stream );
                first_slice = 0;
            }
        }

        start_macroblock();
        trace_out=0;//for test
        glb_rdopt=1;
        encode_one_macroblock( intra );
        trace_out=1;//for test
        glb_rdopt=0;

        write_one_macroblock( 1 );
        terminate_macroblock();
        next_macroblock();
        curr_mb_nr++;
    }
    qcoder_flush( qcoder );
    terminate_pic();
}

